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