|
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 "nsIServiceManager.h" |
|
8 #include "nsResizerFrame.h" |
|
9 #include "nsIContent.h" |
|
10 #include "nsIDocument.h" |
|
11 #include "nsIDOMNodeList.h" |
|
12 #include "nsGkAtoms.h" |
|
13 #include "nsNameSpaceManager.h" |
|
14 #include "nsIDOMElementCSSInlineStyle.h" |
|
15 #include "nsIDOMCSSStyleDeclaration.h" |
|
16 |
|
17 #include "nsPresContext.h" |
|
18 #include "nsFrameManager.h" |
|
19 #include "nsIDocShell.h" |
|
20 #include "nsIDocShellTreeOwner.h" |
|
21 #include "nsIBaseWindow.h" |
|
22 #include "nsPIDOMWindow.h" |
|
23 #include "mozilla/MouseEvents.h" |
|
24 #include "nsContentUtils.h" |
|
25 #include "nsMenuPopupFrame.h" |
|
26 #include "nsIScreenManager.h" |
|
27 #include "mozilla/dom/Element.h" |
|
28 #include "nsError.h" |
|
29 #include <algorithm> |
|
30 |
|
31 using namespace mozilla; |
|
32 |
|
33 // |
|
34 // NS_NewResizerFrame |
|
35 // |
|
36 // Creates a new Resizer frame and returns it |
|
37 // |
|
38 nsIFrame* |
|
39 NS_NewResizerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) |
|
40 { |
|
41 return new (aPresShell) nsResizerFrame(aPresShell, aContext); |
|
42 } |
|
43 |
|
44 NS_IMPL_FRAMEARENA_HELPERS(nsResizerFrame) |
|
45 |
|
46 nsResizerFrame::nsResizerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) |
|
47 :nsTitleBarFrame(aPresShell, aContext) |
|
48 { |
|
49 } |
|
50 |
|
51 nsresult |
|
52 nsResizerFrame::HandleEvent(nsPresContext* aPresContext, |
|
53 WidgetGUIEvent* aEvent, |
|
54 nsEventStatus* aEventStatus) |
|
55 { |
|
56 NS_ENSURE_ARG_POINTER(aEventStatus); |
|
57 if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { |
|
58 return NS_OK; |
|
59 } |
|
60 |
|
61 nsWeakFrame weakFrame(this); |
|
62 bool doDefault = true; |
|
63 |
|
64 switch (aEvent->message) { |
|
65 case NS_TOUCH_START: |
|
66 case NS_MOUSE_BUTTON_DOWN: { |
|
67 if (aEvent->eventStructType == NS_TOUCH_EVENT || |
|
68 (aEvent->eventStructType == NS_MOUSE_EVENT && |
|
69 aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton)) { |
|
70 nsCOMPtr<nsIBaseWindow> window; |
|
71 nsIPresShell* presShell = aPresContext->GetPresShell(); |
|
72 nsIContent* contentToResize = |
|
73 GetContentToResize(presShell, getter_AddRefs(window)); |
|
74 if (contentToResize) { |
|
75 nsIFrame* frameToResize = contentToResize->GetPrimaryFrame(); |
|
76 if (!frameToResize) |
|
77 break; |
|
78 |
|
79 // cache the content rectangle for the frame to resize |
|
80 // GetScreenRectInAppUnits returns the border box rectangle, so |
|
81 // adjust to get the desired content rectangle. |
|
82 nsRect rect = frameToResize->GetScreenRectInAppUnits(); |
|
83 switch (frameToResize->StylePosition()->mBoxSizing) { |
|
84 case NS_STYLE_BOX_SIZING_CONTENT: |
|
85 rect.Deflate(frameToResize->GetUsedPadding()); |
|
86 case NS_STYLE_BOX_SIZING_PADDING: |
|
87 rect.Deflate(frameToResize->GetUsedBorder()); |
|
88 default: |
|
89 break; |
|
90 } |
|
91 |
|
92 mMouseDownRect = rect.ToNearestPixels(aPresContext->AppUnitsPerDevPixel()); |
|
93 doDefault = false; |
|
94 } |
|
95 else { |
|
96 // If there is no window, then resizing isn't allowed. |
|
97 if (!window) |
|
98 break; |
|
99 |
|
100 doDefault = false; |
|
101 |
|
102 // ask the widget implementation to begin a resize drag if it can |
|
103 Direction direction = GetDirection(); |
|
104 nsresult rv = aEvent->widget->BeginResizeDrag(aEvent, |
|
105 direction.mHorizontal, direction.mVertical); |
|
106 // for native drags, don't set the fields below |
|
107 if (rv != NS_ERROR_NOT_IMPLEMENTED) |
|
108 break; |
|
109 |
|
110 // if there's no native resize support, we need to do window |
|
111 // resizing ourselves |
|
112 window->GetPositionAndSize(&mMouseDownRect.x, &mMouseDownRect.y, |
|
113 &mMouseDownRect.width, &mMouseDownRect.height); |
|
114 } |
|
115 |
|
116 // remember current mouse coordinates |
|
117 nsIntPoint refPoint; |
|
118 if (!GetEventPoint(aEvent, refPoint)) |
|
119 return NS_OK; |
|
120 mMouseDownPoint = refPoint + aEvent->widget->WidgetToScreenOffset(); |
|
121 |
|
122 // we're tracking |
|
123 mTrackingMouseMove = true; |
|
124 |
|
125 nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED); |
|
126 } |
|
127 } |
|
128 break; |
|
129 |
|
130 case NS_TOUCH_END: |
|
131 case NS_MOUSE_BUTTON_UP: { |
|
132 if (aEvent->eventStructType == NS_TOUCH_EVENT || |
|
133 (aEvent->eventStructType == NS_MOUSE_EVENT && |
|
134 aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton)) { |
|
135 // we're done tracking. |
|
136 mTrackingMouseMove = false; |
|
137 |
|
138 nsIPresShell::SetCapturingContent(nullptr, 0); |
|
139 |
|
140 doDefault = false; |
|
141 } |
|
142 } |
|
143 break; |
|
144 |
|
145 case NS_TOUCH_MOVE: |
|
146 case NS_MOUSE_MOVE: { |
|
147 if (mTrackingMouseMove) |
|
148 { |
|
149 nsCOMPtr<nsIBaseWindow> window; |
|
150 nsIPresShell* presShell = aPresContext->GetPresShell(); |
|
151 nsCOMPtr<nsIContent> contentToResize = |
|
152 GetContentToResize(presShell, getter_AddRefs(window)); |
|
153 |
|
154 // check if the returned content really is a menupopup |
|
155 nsMenuPopupFrame* menuPopupFrame = nullptr; |
|
156 if (contentToResize) { |
|
157 menuPopupFrame = do_QueryFrame(contentToResize->GetPrimaryFrame()); |
|
158 } |
|
159 |
|
160 // both MouseMove and direction are negative when pointing to the |
|
161 // top and left, and positive when pointing to the bottom and right |
|
162 |
|
163 // retrieve the offset of the mousemove event relative to the mousedown. |
|
164 // The difference is how much the resize needs to be |
|
165 nsIntPoint refPoint; |
|
166 if (!GetEventPoint(aEvent, refPoint)) |
|
167 return NS_OK; |
|
168 nsIntPoint screenPoint(refPoint + aEvent->widget->WidgetToScreenOffset()); |
|
169 nsIntPoint mouseMove(screenPoint - mMouseDownPoint); |
|
170 |
|
171 // Determine which direction to resize by checking the dir attribute. |
|
172 // For windows and menus, ensure that it can be resized in that direction. |
|
173 Direction direction = GetDirection(); |
|
174 if (window || menuPopupFrame) { |
|
175 if (menuPopupFrame) { |
|
176 menuPopupFrame->CanAdjustEdges( |
|
177 (direction.mHorizontal == -1) ? NS_SIDE_LEFT : NS_SIDE_RIGHT, |
|
178 (direction.mVertical == -1) ? NS_SIDE_TOP : NS_SIDE_BOTTOM, mouseMove); |
|
179 } |
|
180 } |
|
181 else if (!contentToResize) { |
|
182 break; // don't do anything if there's nothing to resize |
|
183 } |
|
184 |
|
185 nsIntRect rect = mMouseDownRect; |
|
186 |
|
187 // Check if there are any size constraints on this window. |
|
188 widget::SizeConstraints sizeConstraints; |
|
189 if (window) { |
|
190 nsCOMPtr<nsIWidget> widget; |
|
191 window->GetMainWidget(getter_AddRefs(widget)); |
|
192 sizeConstraints = widget->GetSizeConstraints(); |
|
193 } |
|
194 |
|
195 AdjustDimensions(&rect.x, &rect.width, sizeConstraints.mMinSize.width, |
|
196 sizeConstraints.mMaxSize.width, mouseMove.x, direction.mHorizontal); |
|
197 AdjustDimensions(&rect.y, &rect.height, sizeConstraints.mMinSize.height, |
|
198 sizeConstraints.mMaxSize.height, mouseMove.y, direction.mVertical); |
|
199 |
|
200 // Don't allow resizing a window or a popup past the edge of the screen, |
|
201 // so adjust the rectangle to fit within the available screen area. |
|
202 if (window) { |
|
203 nsCOMPtr<nsIScreen> screen; |
|
204 nsCOMPtr<nsIScreenManager> sm(do_GetService("@mozilla.org/gfx/screenmanager;1")); |
|
205 if (sm) { |
|
206 nsIntRect frameRect = GetScreenRect(); |
|
207 // ScreenForRect requires display pixels, so scale from device pix |
|
208 double scale; |
|
209 window->GetUnscaledDevicePixelsPerCSSPixel(&scale); |
|
210 sm->ScreenForRect(NSToIntRound(frameRect.x / scale), |
|
211 NSToIntRound(frameRect.y / scale), 1, 1, |
|
212 getter_AddRefs(screen)); |
|
213 if (screen) { |
|
214 nsIntRect screenRect; |
|
215 screen->GetRect(&screenRect.x, &screenRect.y, |
|
216 &screenRect.width, &screenRect.height); |
|
217 rect.IntersectRect(rect, screenRect); |
|
218 } |
|
219 } |
|
220 } |
|
221 else if (menuPopupFrame) { |
|
222 nsRect frameRect = menuPopupFrame->GetScreenRectInAppUnits(); |
|
223 nsIFrame* rootFrame = aPresContext->PresShell()->FrameManager()->GetRootFrame(); |
|
224 nsRect rootScreenRect = rootFrame->GetScreenRectInAppUnits(); |
|
225 |
|
226 nsPopupLevel popupLevel = menuPopupFrame->PopupLevel(); |
|
227 nsRect screenRect = menuPopupFrame->GetConstraintRect(frameRect, rootScreenRect, popupLevel); |
|
228 // round using ToInsidePixels as it's better to be a pixel too small |
|
229 // than be too large. If the popup is too large it could get flipped |
|
230 // to the opposite side of the anchor point while resizing. |
|
231 nsIntRect screenRectPixels = screenRect.ToInsidePixels(aPresContext->AppUnitsPerDevPixel()); |
|
232 rect.IntersectRect(rect, screenRectPixels); |
|
233 } |
|
234 |
|
235 if (contentToResize) { |
|
236 // convert the rectangle into css pixels. When changing the size in a |
|
237 // direction, don't allow the new size to be less that the resizer's |
|
238 // size. This ensures that content isn't resized too small as to make |
|
239 // the resizer invisible. |
|
240 nsRect appUnitsRect = rect.ToAppUnits(aPresContext->AppUnitsPerDevPixel()); |
|
241 if (appUnitsRect.width < mRect.width && mouseMove.x) |
|
242 appUnitsRect.width = mRect.width; |
|
243 if (appUnitsRect.height < mRect.height && mouseMove.y) |
|
244 appUnitsRect.height = mRect.height; |
|
245 nsIntRect cssRect = appUnitsRect.ToInsidePixels(nsPresContext::AppUnitsPerCSSPixel()); |
|
246 |
|
247 nsIntRect oldRect; |
|
248 nsWeakFrame weakFrame(menuPopupFrame); |
|
249 if (menuPopupFrame) { |
|
250 nsCOMPtr<nsIWidget> widget = menuPopupFrame->GetWidget(); |
|
251 if (widget) |
|
252 widget->GetScreenBounds(oldRect); |
|
253 |
|
254 // convert the new rectangle into outer window coordinates |
|
255 nsIntPoint clientOffset = widget->GetClientOffset(); |
|
256 rect.x -= clientOffset.x; |
|
257 rect.y -= clientOffset.y; |
|
258 } |
|
259 |
|
260 SizeInfo sizeInfo, originalSizeInfo; |
|
261 sizeInfo.width.AppendInt(cssRect.width); |
|
262 sizeInfo.height.AppendInt(cssRect.height); |
|
263 ResizeContent(contentToResize, direction, sizeInfo, &originalSizeInfo); |
|
264 MaybePersistOriginalSize(contentToResize, originalSizeInfo); |
|
265 |
|
266 // Move the popup to the new location unless it is anchored, since |
|
267 // the position shouldn't change. nsMenuPopupFrame::SetPopupPosition |
|
268 // will instead ensure that the popup's position is anchored at the |
|
269 // right place. |
|
270 if (weakFrame.IsAlive() && |
|
271 (oldRect.x != rect.x || oldRect.y != rect.y) && |
|
272 (!menuPopupFrame->IsAnchored() || |
|
273 menuPopupFrame->PopupLevel() != ePopupLevelParent)) { |
|
274 |
|
275 rect.x = aPresContext->DevPixelsToIntCSSPixels(rect.x); |
|
276 rect.y = aPresContext->DevPixelsToIntCSSPixels(rect.y); |
|
277 menuPopupFrame->MoveTo(rect.x, rect.y, true); |
|
278 } |
|
279 } |
|
280 else { |
|
281 window->SetPositionAndSize(rect.x, rect.y, rect.width, rect.height, true); // do the repaint. |
|
282 } |
|
283 |
|
284 doDefault = false; |
|
285 } |
|
286 } |
|
287 break; |
|
288 |
|
289 case NS_MOUSE_CLICK: { |
|
290 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); |
|
291 if (mouseEvent->IsLeftClickEvent()) { |
|
292 MouseClicked(aPresContext, mouseEvent); |
|
293 } |
|
294 break; |
|
295 } |
|
296 case NS_MOUSE_DOUBLECLICK: |
|
297 if (aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) { |
|
298 nsCOMPtr<nsIBaseWindow> window; |
|
299 nsIPresShell* presShell = aPresContext->GetPresShell(); |
|
300 nsIContent* contentToResize = |
|
301 GetContentToResize(presShell, getter_AddRefs(window)); |
|
302 if (contentToResize) { |
|
303 nsMenuPopupFrame* menuPopupFrame = do_QueryFrame(contentToResize->GetPrimaryFrame()); |
|
304 if (menuPopupFrame) |
|
305 break; // Don't restore original sizing for menupopup frames until |
|
306 // we handle screen constraints here. (Bug 357725) |
|
307 |
|
308 RestoreOriginalSize(contentToResize); |
|
309 } |
|
310 } |
|
311 break; |
|
312 } |
|
313 |
|
314 if (!doDefault) |
|
315 *aEventStatus = nsEventStatus_eConsumeNoDefault; |
|
316 |
|
317 if (doDefault && weakFrame.IsAlive()) |
|
318 return nsTitleBarFrame::HandleEvent(aPresContext, aEvent, aEventStatus); |
|
319 |
|
320 return NS_OK; |
|
321 } |
|
322 |
|
323 nsIContent* |
|
324 nsResizerFrame::GetContentToResize(nsIPresShell* aPresShell, nsIBaseWindow** aWindow) |
|
325 { |
|
326 *aWindow = nullptr; |
|
327 |
|
328 nsAutoString elementid; |
|
329 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::element, elementid); |
|
330 if (elementid.IsEmpty()) { |
|
331 // If the resizer is in a popup, resize the popup's widget, otherwise |
|
332 // resize the widget associated with the window. |
|
333 nsIFrame* popup = GetParent(); |
|
334 while (popup) { |
|
335 nsMenuPopupFrame* popupFrame = do_QueryFrame(popup); |
|
336 if (popupFrame) { |
|
337 return popupFrame->GetContent(); |
|
338 } |
|
339 popup = popup->GetParent(); |
|
340 } |
|
341 |
|
342 // don't allow resizing windows in content shells |
|
343 nsCOMPtr<nsIDocShellTreeItem> dsti = aPresShell->GetPresContext()->GetDocShell(); |
|
344 if (!dsti || dsti->ItemType() != nsIDocShellTreeItem::typeChrome) { |
|
345 // don't allow resizers in content shells, except for the viewport |
|
346 // scrollbar which doesn't have a parent |
|
347 nsIContent* nonNativeAnon = mContent->FindFirstNonChromeOnlyAccessContent(); |
|
348 if (!nonNativeAnon || nonNativeAnon->GetParent()) { |
|
349 return nullptr; |
|
350 } |
|
351 } |
|
352 |
|
353 // get the document and the window - should this be cached? |
|
354 nsPIDOMWindow *domWindow = aPresShell->GetDocument()->GetWindow(); |
|
355 if (domWindow) { |
|
356 nsCOMPtr<nsIDocShell> docShell = domWindow->GetDocShell(); |
|
357 if (docShell) { |
|
358 nsCOMPtr<nsIDocShellTreeOwner> treeOwner; |
|
359 docShell->GetTreeOwner(getter_AddRefs(treeOwner)); |
|
360 if (treeOwner) { |
|
361 CallQueryInterface(treeOwner, aWindow); |
|
362 } |
|
363 } |
|
364 } |
|
365 |
|
366 return nullptr; |
|
367 } |
|
368 |
|
369 if (elementid.EqualsLiteral("_parent")) { |
|
370 // return the parent, but skip over native anonymous content |
|
371 nsIContent* parent = mContent->GetParent(); |
|
372 return parent ? parent->FindFirstNonChromeOnlyAccessContent() : nullptr; |
|
373 } |
|
374 |
|
375 return aPresShell->GetDocument()->GetElementById(elementid); |
|
376 } |
|
377 |
|
378 void |
|
379 nsResizerFrame::AdjustDimensions(int32_t* aPos, int32_t* aSize, |
|
380 int32_t aMinSize, int32_t aMaxSize, |
|
381 int32_t aMovement, int8_t aResizerDirection) |
|
382 { |
|
383 int32_t oldSize = *aSize; |
|
384 |
|
385 *aSize += aResizerDirection * aMovement; |
|
386 // use one as a minimum size or the element could disappear |
|
387 if (*aSize < 1) |
|
388 *aSize = 1; |
|
389 |
|
390 // Constrain the size within the minimum and maximum size. |
|
391 *aSize = std::max(aMinSize, std::min(aMaxSize, *aSize)); |
|
392 |
|
393 // For left and top resizers, the window must be moved left by the same |
|
394 // amount that the window was resized. |
|
395 if (aResizerDirection == -1) |
|
396 *aPos += oldSize - *aSize; |
|
397 } |
|
398 |
|
399 /* static */ void |
|
400 nsResizerFrame::ResizeContent(nsIContent* aContent, const Direction& aDirection, |
|
401 const SizeInfo& aSizeInfo, SizeInfo* aOriginalSizeInfo) |
|
402 { |
|
403 // for XUL elements, just set the width and height attributes. For |
|
404 // other elements, set style.width and style.height |
|
405 if (aContent->IsXUL()) { |
|
406 if (aOriginalSizeInfo) { |
|
407 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::width, |
|
408 aOriginalSizeInfo->width); |
|
409 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::height, |
|
410 aOriginalSizeInfo->height); |
|
411 } |
|
412 // only set the property if the element could have changed in that direction |
|
413 if (aDirection.mHorizontal) { |
|
414 aContent->SetAttr(kNameSpaceID_None, nsGkAtoms::width, aSizeInfo.width, true); |
|
415 } |
|
416 if (aDirection.mVertical) { |
|
417 aContent->SetAttr(kNameSpaceID_None, nsGkAtoms::height, aSizeInfo.height, true); |
|
418 } |
|
419 } |
|
420 else { |
|
421 nsCOMPtr<nsIDOMElementCSSInlineStyle> inlineStyleContent = |
|
422 do_QueryInterface(aContent); |
|
423 if (inlineStyleContent) { |
|
424 nsCOMPtr<nsIDOMCSSStyleDeclaration> decl; |
|
425 inlineStyleContent->GetStyle(getter_AddRefs(decl)); |
|
426 |
|
427 if (aOriginalSizeInfo) { |
|
428 decl->GetPropertyValue(NS_LITERAL_STRING("width"), |
|
429 aOriginalSizeInfo->width); |
|
430 decl->GetPropertyValue(NS_LITERAL_STRING("height"), |
|
431 aOriginalSizeInfo->height); |
|
432 } |
|
433 |
|
434 // only set the property if the element could have changed in that direction |
|
435 if (aDirection.mHorizontal) { |
|
436 nsAutoString widthstr(aSizeInfo.width); |
|
437 if (!widthstr.IsEmpty() && |
|
438 !Substring(widthstr, widthstr.Length() - 2, 2).EqualsLiteral("px")) |
|
439 widthstr.AppendLiteral("px"); |
|
440 decl->SetProperty(NS_LITERAL_STRING("width"), widthstr, EmptyString()); |
|
441 } |
|
442 if (aDirection.mVertical) { |
|
443 nsAutoString heightstr(aSizeInfo.height); |
|
444 if (!heightstr.IsEmpty() && |
|
445 !Substring(heightstr, heightstr.Length() - 2, 2).EqualsLiteral("px")) |
|
446 heightstr.AppendLiteral("px"); |
|
447 decl->SetProperty(NS_LITERAL_STRING("height"), heightstr, EmptyString()); |
|
448 } |
|
449 } |
|
450 } |
|
451 } |
|
452 |
|
453 /* static */ void |
|
454 nsResizerFrame::MaybePersistOriginalSize(nsIContent* aContent, |
|
455 const SizeInfo& aSizeInfo) |
|
456 { |
|
457 nsresult rv; |
|
458 |
|
459 aContent->GetProperty(nsGkAtoms::_moz_original_size, &rv); |
|
460 if (rv != NS_PROPTABLE_PROP_NOT_THERE) |
|
461 return; |
|
462 |
|
463 nsAutoPtr<SizeInfo> sizeInfo(new SizeInfo(aSizeInfo)); |
|
464 rv = aContent->SetProperty(nsGkAtoms::_moz_original_size, sizeInfo.get(), |
|
465 nsINode::DeleteProperty<nsResizerFrame::SizeInfo>); |
|
466 if (NS_SUCCEEDED(rv)) |
|
467 sizeInfo.forget(); |
|
468 } |
|
469 |
|
470 /* static */ void |
|
471 nsResizerFrame::RestoreOriginalSize(nsIContent* aContent) |
|
472 { |
|
473 nsresult rv; |
|
474 SizeInfo* sizeInfo = |
|
475 static_cast<SizeInfo*>(aContent->GetProperty(nsGkAtoms::_moz_original_size, |
|
476 &rv)); |
|
477 if (NS_FAILED(rv)) |
|
478 return; |
|
479 |
|
480 NS_ASSERTION(sizeInfo, "We set a null sizeInfo!?"); |
|
481 Direction direction = {1, 1}; |
|
482 ResizeContent(aContent, direction, *sizeInfo, nullptr); |
|
483 aContent->DeleteProperty(nsGkAtoms::_moz_original_size); |
|
484 } |
|
485 |
|
486 /* returns a Direction struct containing the horizontal and vertical direction |
|
487 */ |
|
488 nsResizerFrame::Direction |
|
489 nsResizerFrame::GetDirection() |
|
490 { |
|
491 static const nsIContent::AttrValuesArray strings[] = |
|
492 {&nsGkAtoms::topleft, &nsGkAtoms::top, &nsGkAtoms::topright, |
|
493 &nsGkAtoms::left, &nsGkAtoms::right, |
|
494 &nsGkAtoms::bottomleft, &nsGkAtoms::bottom, &nsGkAtoms::bottomright, |
|
495 &nsGkAtoms::bottomstart, &nsGkAtoms::bottomend, |
|
496 nullptr}; |
|
497 |
|
498 static const Direction directions[] = |
|
499 {{-1, -1}, {0, -1}, {1, -1}, |
|
500 {-1, 0}, {1, 0}, |
|
501 {-1, 1}, {0, 1}, {1, 1}, |
|
502 {-1, 1}, {1, 1} |
|
503 }; |
|
504 |
|
505 if (!GetContent()) |
|
506 return directions[0]; // default: topleft |
|
507 |
|
508 int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, |
|
509 nsGkAtoms::dir, |
|
510 strings, eCaseMatters); |
|
511 if(index < 0) |
|
512 return directions[0]; // default: topleft |
|
513 else if (index >= 8 && StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) { |
|
514 // Directions 8 and higher are RTL-aware directions and should reverse the |
|
515 // horizontal component if RTL. |
|
516 Direction direction = directions[index]; |
|
517 direction.mHorizontal *= -1; |
|
518 return direction; |
|
519 } |
|
520 return directions[index]; |
|
521 } |
|
522 |
|
523 void |
|
524 nsResizerFrame::MouseClicked(nsPresContext* aPresContext, |
|
525 WidgetMouseEvent* aEvent) |
|
526 { |
|
527 // Execute the oncommand event handler. |
|
528 nsContentUtils::DispatchXULCommand(mContent, |
|
529 aEvent && aEvent->mFlags.mIsTrusted); |
|
530 } |