/src/mozilla-central/view/nsView.cpp
Line | Count | Source (jump to first uncovered line) |
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 "nsView.h" |
7 | | |
8 | | #include "mozilla/Attributes.h" |
9 | | #include "mozilla/BasicEvents.h" |
10 | | #include "mozilla/DebugOnly.h" |
11 | | #include "mozilla/IntegerPrintfMacros.h" |
12 | | #include "mozilla/Likely.h" |
13 | | #include "mozilla/Poison.h" |
14 | | #include "nsIWidget.h" |
15 | | #include "nsViewManager.h" |
16 | | #include "nsIFrame.h" |
17 | | #include "nsPresArena.h" |
18 | | #include "nsXULPopupManager.h" |
19 | | #include "nsIWidgetListener.h" |
20 | | #include "nsContentUtils.h" // for nsAutoScriptBlocker |
21 | | #include "mozilla/TimelineConsumers.h" |
22 | | #include "mozilla/CompositeTimelineMarker.h" |
23 | | |
24 | | using namespace mozilla; |
25 | | |
26 | | static bool sShowPreviousPage = true; |
27 | | |
28 | | nsView::nsView(nsViewManager* aViewManager, nsViewVisibility aVisibility) |
29 | | : mViewManager(aViewManager) |
30 | | , mParent(nullptr) |
31 | | , mNextSibling(nullptr) |
32 | | , mFirstChild(nullptr) |
33 | | , mFrame(nullptr) |
34 | | , mDirtyRegion(nullptr) |
35 | | , mZIndex(0) |
36 | | , mVis(aVisibility) |
37 | | , mPosX(0) |
38 | | , mPosY(0) |
39 | | , mVFlags(0) |
40 | | , mWidgetIsTopLevel(false) |
41 | | , mForcedRepaint(false) |
42 | | , mNeedsWindowPropertiesSync(false) |
43 | 0 | { |
44 | 0 | MOZ_COUNT_CTOR(nsView); |
45 | 0 |
|
46 | 0 | // Views should be transparent by default. Not being transparent is |
47 | 0 | // a promise that the view will paint all its pixels opaquely. Views |
48 | 0 | // should make this promise explicitly by calling |
49 | 0 | // SetViewContentTransparency. |
50 | 0 |
|
51 | 0 | static bool sShowPreviousPageInitialized = false; |
52 | 0 | if (!sShowPreviousPageInitialized) { |
53 | 0 | Preferences::AddBoolVarCache(&sShowPreviousPage, "layout.show_previous_page", true); |
54 | 0 | sShowPreviousPageInitialized = true; |
55 | 0 | } |
56 | 0 | } |
57 | | |
58 | | void nsView::DropMouseGrabbing() |
59 | 0 | { |
60 | 0 | nsIPresShell* presShell = mViewManager->GetPresShell(); |
61 | 0 | if (presShell) |
62 | 0 | presShell->ClearMouseCaptureOnView(this); |
63 | 0 | } |
64 | | |
65 | | nsView::~nsView() |
66 | 0 | { |
67 | 0 | MOZ_COUNT_DTOR(nsView); |
68 | 0 |
|
69 | 0 | while (GetFirstChild()) |
70 | 0 | { |
71 | 0 | nsView* child = GetFirstChild(); |
72 | 0 | if (child->GetViewManager() == mViewManager) { |
73 | 0 | child->Destroy(); |
74 | 0 | } else { |
75 | 0 | // just unhook it. Someone else will want to destroy this. |
76 | 0 | RemoveChild(child); |
77 | 0 | } |
78 | 0 | } |
79 | 0 |
|
80 | 0 | if (mViewManager) |
81 | 0 | { |
82 | 0 | DropMouseGrabbing(); |
83 | 0 |
|
84 | 0 | nsView *rootView = mViewManager->GetRootView(); |
85 | 0 |
|
86 | 0 | if (rootView) |
87 | 0 | { |
88 | 0 | // Root views can have parents! |
89 | 0 | if (mParent) |
90 | 0 | { |
91 | 0 | mViewManager->RemoveChild(this); |
92 | 0 | } |
93 | 0 |
|
94 | 0 | if (rootView == this) |
95 | 0 | { |
96 | 0 | // Inform the view manager that the root view has gone away... |
97 | 0 | mViewManager->SetRootView(nullptr); |
98 | 0 | } |
99 | 0 | } |
100 | 0 | else if (mParent) |
101 | 0 | { |
102 | 0 | mParent->RemoveChild(this); |
103 | 0 | } |
104 | 0 |
|
105 | 0 | mViewManager = nullptr; |
106 | 0 | } |
107 | 0 | else if (mParent) |
108 | 0 | { |
109 | 0 | mParent->RemoveChild(this); |
110 | 0 | } |
111 | 0 |
|
112 | 0 | if (mPreviousWindow) { |
113 | 0 | mPreviousWindow->SetPreviouslyAttachedWidgetListener(nullptr); |
114 | 0 | } |
115 | 0 |
|
116 | 0 | // Destroy and release the widget |
117 | 0 | DestroyWidget(); |
118 | 0 |
|
119 | 0 | delete mDirtyRegion; |
120 | 0 | } |
121 | | |
122 | | class DestroyWidgetRunnable : public Runnable { |
123 | | public: |
124 | | NS_DECL_NSIRUNNABLE |
125 | | |
126 | | explicit DestroyWidgetRunnable(nsIWidget* aWidget) |
127 | | : mozilla::Runnable("DestroyWidgetRunnable") |
128 | | , mWidget(aWidget) |
129 | 0 | { |
130 | 0 | } |
131 | | |
132 | | private: |
133 | | nsCOMPtr<nsIWidget> mWidget; |
134 | | }; |
135 | | |
136 | | NS_IMETHODIMP DestroyWidgetRunnable::Run() |
137 | 0 | { |
138 | 0 | mWidget->Destroy(); |
139 | 0 | mWidget = nullptr; |
140 | 0 | return NS_OK; |
141 | 0 | } |
142 | | |
143 | | |
144 | | void nsView::DestroyWidget() |
145 | 0 | { |
146 | 0 | if (mWindow) |
147 | 0 | { |
148 | 0 | // If we are not attached to a base window, we're going to tear down our |
149 | 0 | // widget here. However, if we're attached to somebody elses widget, we |
150 | 0 | // want to leave the widget alone: don't reset the client data or call |
151 | 0 | // Destroy. Just clear our event view ptr and free our reference to it. |
152 | 0 | if (mWidgetIsTopLevel) { |
153 | 0 | mWindow->SetAttachedWidgetListener(nullptr); |
154 | 0 | } |
155 | 0 | else { |
156 | 0 | mWindow->SetWidgetListener(nullptr); |
157 | 0 |
|
158 | 0 | nsCOMPtr<nsIRunnable> widgetDestroyer = |
159 | 0 | new DestroyWidgetRunnable(mWindow); |
160 | 0 |
|
161 | 0 | // Don't leak if we happen to arrive here after the main thread |
162 | 0 | // has disappeared. |
163 | 0 | nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); |
164 | 0 | if (mainThread) { |
165 | 0 | mainThread->Dispatch(widgetDestroyer.forget(), NS_DISPATCH_NORMAL); |
166 | 0 | } |
167 | 0 | } |
168 | 0 |
|
169 | 0 | mWindow = nullptr; |
170 | 0 | } |
171 | 0 | } |
172 | | |
173 | | nsView* nsView::GetViewFor(nsIWidget* aWidget) |
174 | 0 | { |
175 | 0 | MOZ_ASSERT(nullptr != aWidget, "null widget ptr"); |
176 | 0 |
|
177 | 0 | nsIWidgetListener* listener = aWidget->GetWidgetListener(); |
178 | 0 | if (listener) { |
179 | 0 | nsView* view = listener->GetView(); |
180 | 0 | if (view) |
181 | 0 | return view; |
182 | 0 | } |
183 | 0 | |
184 | 0 | listener = aWidget->GetAttachedWidgetListener(); |
185 | 0 | return listener ? listener->GetView() : nullptr; |
186 | 0 | } |
187 | | |
188 | | void nsView::Destroy() |
189 | 0 | { |
190 | 0 | this->~nsView(); |
191 | 0 | mozWritePoison(this, sizeof(*this)); |
192 | 0 | nsView::operator delete(this); |
193 | 0 | } |
194 | | |
195 | | void nsView::SetPosition(nscoord aX, nscoord aY) |
196 | 0 | { |
197 | 0 | mDimBounds.MoveBy(aX - mPosX, aY - mPosY); |
198 | 0 | mPosX = aX; |
199 | 0 | mPosY = aY; |
200 | 0 |
|
201 | 0 | NS_ASSERTION(GetParent() || (aX == 0 && aY == 0), |
202 | 0 | "Don't try to move the root widget to something non-zero"); |
203 | 0 |
|
204 | 0 | ResetWidgetBounds(true, false); |
205 | 0 | } |
206 | | |
207 | | void nsView::ResetWidgetBounds(bool aRecurse, bool aForceSync) |
208 | 0 | { |
209 | 0 | if (mWindow) { |
210 | 0 | if (!aForceSync) { |
211 | 0 | // Don't change widget geometry synchronously, since that can |
212 | 0 | // cause synchronous painting. |
213 | 0 | mViewManager->PostPendingUpdate(); |
214 | 0 | } else { |
215 | 0 | DoResetWidgetBounds(false, true); |
216 | 0 | } |
217 | 0 | return; |
218 | 0 | } |
219 | 0 |
|
220 | 0 | if (aRecurse) { |
221 | 0 | // reposition any widgets under this view |
222 | 0 | for (nsView* v = GetFirstChild(); v; v = v->GetNextSibling()) { |
223 | 0 | v->ResetWidgetBounds(true, aForceSync); |
224 | 0 | } |
225 | 0 | } |
226 | 0 | } |
227 | | |
228 | | bool nsView::IsEffectivelyVisible() |
229 | 0 | { |
230 | 0 | for (nsView* v = this; v; v = v->mParent) { |
231 | 0 | if (v->GetVisibility() == nsViewVisibility_kHide) |
232 | 0 | return false; |
233 | 0 | } |
234 | 0 | return true; |
235 | 0 | } |
236 | | |
237 | | LayoutDeviceIntRect nsView::CalcWidgetBounds(nsWindowType aType) |
238 | 0 | { |
239 | 0 | int32_t p2a = mViewManager->AppUnitsPerDevPixel(); |
240 | 0 |
|
241 | 0 | nsRect viewBounds(mDimBounds); |
242 | 0 |
|
243 | 0 | nsView* parent = GetParent(); |
244 | 0 | nsIWidget* parentWidget = nullptr; |
245 | 0 | if (parent) { |
246 | 0 | nsPoint offset; |
247 | 0 | parentWidget = parent->GetNearestWidget(&offset, p2a); |
248 | 0 | // make viewBounds be relative to the parent widget, in appunits |
249 | 0 | viewBounds += offset; |
250 | 0 |
|
251 | 0 | if (parentWidget && aType == eWindowType_popup && |
252 | 0 | IsEffectivelyVisible()) { |
253 | 0 | // put offset into screen coordinates. (based on client area origin) |
254 | 0 | LayoutDeviceIntPoint screenPoint = parentWidget->WidgetToScreenOffset(); |
255 | 0 | viewBounds += nsPoint(NSIntPixelsToAppUnits(screenPoint.x, p2a), |
256 | 0 | NSIntPixelsToAppUnits(screenPoint.y, p2a)); |
257 | 0 | } |
258 | 0 | } |
259 | 0 |
|
260 | 0 | // Compute widget bounds in device pixels |
261 | 0 | LayoutDeviceIntRect newBounds = |
262 | 0 | LayoutDeviceIntRect::FromUnknownRect(viewBounds.ToNearestPixels(p2a)); |
263 | 0 |
|
264 | 0 | #if defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK) |
265 | 0 | // cocoa and GTK round widget coordinates to the nearest global "display |
266 | 0 | // pixel" integer value. So we avoid fractional display pixel values by |
267 | 0 | // rounding to the nearest value that won't yield a fractional display pixel. |
268 | 0 | nsIWidget* widget = parentWidget ? parentWidget : mWindow.get(); |
269 | 0 | uint32_t round; |
270 | 0 | if (aType == eWindowType_popup && widget && |
271 | 0 | ((round = widget->RoundsWidgetCoordinatesTo()) > 1)) { |
272 | 0 | LayoutDeviceIntSize pixelRoundedSize = newBounds.Size(); |
273 | 0 | // round the top left and bottom right to the nearest round pixel |
274 | 0 | newBounds.x = NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.x, p2a) / round) * round; |
275 | 0 | newBounds.y = NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.y, p2a) / round) * round; |
276 | 0 | newBounds.width = |
277 | 0 | NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.XMost(), p2a) / round) * round - newBounds.x; |
278 | 0 | newBounds.height = |
279 | 0 | NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.YMost(), p2a) / round) * round - newBounds.y; |
280 | 0 | // but if that makes the widget larger then our frame may not paint the |
281 | 0 | // extra pixels, so reduce the size to the nearest round value |
282 | 0 | if (newBounds.width > pixelRoundedSize.width) { |
283 | 0 | newBounds.width -= round; |
284 | 0 | } |
285 | 0 | if (newBounds.height > pixelRoundedSize.height) { |
286 | 0 | newBounds.height -= round; |
287 | 0 | } |
288 | 0 | } |
289 | 0 | #endif |
290 | 0 |
|
291 | 0 | // Compute where the top-left of our widget ended up relative to the parent |
292 | 0 | // widget, in appunits. |
293 | 0 | nsPoint roundedOffset(NSIntPixelsToAppUnits(newBounds.X(), p2a), |
294 | 0 | NSIntPixelsToAppUnits(newBounds.Y(), p2a)); |
295 | 0 |
|
296 | 0 | // mViewToWidgetOffset is added to coordinates relative to the view origin |
297 | 0 | // to get coordinates relative to the widget. |
298 | 0 | // The view origin, relative to the parent widget, is at |
299 | 0 | // (mPosX,mPosY) - mDimBounds.TopLeft() + viewBounds.TopLeft(). |
300 | 0 | // Our widget, relative to the parent widget, is roundedOffset. |
301 | 0 | mViewToWidgetOffset = nsPoint(mPosX, mPosY) |
302 | 0 | - mDimBounds.TopLeft() + viewBounds.TopLeft() - roundedOffset; |
303 | 0 |
|
304 | 0 | return newBounds; |
305 | 0 | } |
306 | | |
307 | | void nsView::DoResetWidgetBounds(bool aMoveOnly, |
308 | 0 | bool aInvalidateChangedSize) { |
309 | 0 | // The geometry of a root view's widget is controlled externally, |
310 | 0 | // NOT by sizing or positioning the view |
311 | 0 | if (mViewManager->GetRootView() == this) { |
312 | 0 | return; |
313 | 0 | } |
314 | 0 | |
315 | 0 | MOZ_ASSERT(mWindow, "Why was this called??"); |
316 | 0 |
|
317 | 0 | // Hold this ref to make sure it stays alive. |
318 | 0 | nsCOMPtr<nsIWidget> widget = mWindow; |
319 | 0 |
|
320 | 0 | // Stash a copy of these and use them so we can handle this being deleted (say |
321 | 0 | // from sync painting/flushing from Show/Move/Resize on the widget). |
322 | 0 | LayoutDeviceIntRect newBounds; |
323 | 0 | RefPtr<nsDeviceContext> dx = mViewManager->GetDeviceContext(); |
324 | 0 |
|
325 | 0 | nsWindowType type = widget->WindowType(); |
326 | 0 |
|
327 | 0 | LayoutDeviceIntRect curBounds = widget->GetClientBounds(); |
328 | 0 | bool invisiblePopup = type == eWindowType_popup && |
329 | 0 | ((curBounds.IsEmpty() && mDimBounds.IsEmpty()) || |
330 | 0 | mVis == nsViewVisibility_kHide); |
331 | 0 |
|
332 | 0 | if (invisiblePopup) { |
333 | 0 | // We're going to hit the early exit below, avoid calling CalcWidgetBounds. |
334 | 0 | } else { |
335 | 0 | newBounds = CalcWidgetBounds(type); |
336 | 0 | invisiblePopup = newBounds.IsEmpty(); |
337 | 0 | } |
338 | 0 |
|
339 | 0 | bool curVisibility = widget->IsVisible(); |
340 | 0 | bool newVisibility = IsEffectivelyVisible(); |
341 | 0 | if (curVisibility && !newVisibility) { |
342 | 0 | widget->Show(false); |
343 | 0 | } |
344 | 0 |
|
345 | 0 | if (invisiblePopup) { |
346 | 0 | // Don't manipulate empty or hidden popup widgets. For example there's no |
347 | 0 | // point moving hidden comboboxes around, or doing X server roundtrips |
348 | 0 | // to compute their true screen position. This could mean that WidgetToScreen |
349 | 0 | // operations on these widgets don't return up-to-date values, but popup |
350 | 0 | // positions aren't reliable anyway because of correction to be on or off-screen. |
351 | 0 | return; |
352 | 0 | } |
353 | 0 | |
354 | 0 | bool changedPos = curBounds.TopLeft() != newBounds.TopLeft(); |
355 | 0 | bool changedSize = curBounds.Size() != newBounds.Size(); |
356 | 0 |
|
357 | 0 | // Child views are never attached to top level widgets, this is safe. |
358 | 0 |
|
359 | 0 | // Coordinates are converted to desktop pixels for window Move/Resize APIs, |
360 | 0 | // because of the potential for device-pixel coordinate spaces for mixed |
361 | 0 | // hidpi/lodpi screens to overlap each other and result in bad placement |
362 | 0 | // (bug 814434). |
363 | 0 | DesktopToLayoutDeviceScale scale = dx->GetDesktopToDeviceScale(); |
364 | 0 |
|
365 | 0 | DesktopRect deskRect = newBounds / scale; |
366 | 0 | if (changedPos) { |
367 | 0 | if (changedSize && !aMoveOnly) { |
368 | 0 | widget->ResizeClient(deskRect.X(), deskRect.Y(), |
369 | 0 | deskRect.Width(), deskRect.Height(), |
370 | 0 | aInvalidateChangedSize); |
371 | 0 | } else { |
372 | 0 | widget->MoveClient(deskRect.X(), deskRect.Y()); |
373 | 0 | } |
374 | 0 | } else { |
375 | 0 | if (changedSize && !aMoveOnly) { |
376 | 0 | widget->ResizeClient(deskRect.Width(), deskRect.Height(), |
377 | 0 | aInvalidateChangedSize); |
378 | 0 | } // else do nothing! |
379 | 0 | } |
380 | 0 |
|
381 | 0 | if (!curVisibility && newVisibility) { |
382 | 0 | widget->Show(true); |
383 | 0 | } |
384 | 0 | } |
385 | | |
386 | | void nsView::SetDimensions(const nsRect& aRect, bool aPaint, bool aResizeWidget) |
387 | 0 | { |
388 | 0 | nsRect dims = aRect; |
389 | 0 | dims.MoveBy(mPosX, mPosY); |
390 | 0 |
|
391 | 0 | // Don't use nsRect's operator== here, since it returns true when |
392 | 0 | // both rects are empty even if they have different widths and we |
393 | 0 | // have cases where that sort of thing matters to us. |
394 | 0 | if (mDimBounds.TopLeft() == dims.TopLeft() && |
395 | 0 | mDimBounds.Size() == dims.Size()) { |
396 | 0 | return; |
397 | 0 | } |
398 | 0 | |
399 | 0 | mDimBounds = dims; |
400 | 0 |
|
401 | 0 | if (aResizeWidget) { |
402 | 0 | ResetWidgetBounds(false, false); |
403 | 0 | } |
404 | 0 | } |
405 | | |
406 | | void nsView::NotifyEffectiveVisibilityChanged(bool aEffectivelyVisible) |
407 | 0 | { |
408 | 0 | if (!aEffectivelyVisible) |
409 | 0 | { |
410 | 0 | DropMouseGrabbing(); |
411 | 0 | } |
412 | 0 |
|
413 | 0 | SetForcedRepaint(true); |
414 | 0 |
|
415 | 0 | if (nullptr != mWindow) |
416 | 0 | { |
417 | 0 | ResetWidgetBounds(false, false); |
418 | 0 | } |
419 | 0 |
|
420 | 0 | for (nsView* child = mFirstChild; child; child = child->mNextSibling) { |
421 | 0 | if (child->mVis == nsViewVisibility_kHide) { |
422 | 0 | // It was effectively hidden and still is |
423 | 0 | continue; |
424 | 0 | } |
425 | 0 | // Our child is visible if we are |
426 | 0 | child->NotifyEffectiveVisibilityChanged(aEffectivelyVisible); |
427 | 0 | } |
428 | 0 | } |
429 | | |
430 | | void nsView::SetVisibility(nsViewVisibility aVisibility) |
431 | 0 | { |
432 | 0 | mVis = aVisibility; |
433 | 0 | NotifyEffectiveVisibilityChanged(IsEffectivelyVisible()); |
434 | 0 | } |
435 | | |
436 | | void nsView::SetFloating(bool aFloatingView) |
437 | 0 | { |
438 | 0 | if (aFloatingView) |
439 | 0 | mVFlags |= NS_VIEW_FLAG_FLOATING; |
440 | 0 | else |
441 | 0 | mVFlags &= ~NS_VIEW_FLAG_FLOATING; |
442 | 0 | } |
443 | | |
444 | | void nsView::InvalidateHierarchy() |
445 | 0 | { |
446 | 0 | if (mViewManager->GetRootView() == this) |
447 | 0 | mViewManager->InvalidateHierarchy(); |
448 | 0 |
|
449 | 0 | for (nsView *child = mFirstChild; child; child = child->GetNextSibling()) |
450 | 0 | child->InvalidateHierarchy(); |
451 | 0 | } |
452 | | |
453 | | void nsView::InsertChild(nsView *aChild, nsView *aSibling) |
454 | 0 | { |
455 | 0 | MOZ_ASSERT(nullptr != aChild, "null ptr"); |
456 | 0 |
|
457 | 0 | if (nullptr != aChild) |
458 | 0 | { |
459 | 0 | if (nullptr != aSibling) |
460 | 0 | { |
461 | | #ifdef DEBUG |
462 | | NS_ASSERTION(aSibling->GetParent() == this, "tried to insert view with invalid sibling"); |
463 | | #endif |
464 | | //insert after sibling |
465 | 0 | aChild->SetNextSibling(aSibling->GetNextSibling()); |
466 | 0 | aSibling->SetNextSibling(aChild); |
467 | 0 | } |
468 | 0 | else |
469 | 0 | { |
470 | 0 | aChild->SetNextSibling(mFirstChild); |
471 | 0 | mFirstChild = aChild; |
472 | 0 | } |
473 | 0 | aChild->SetParent(this); |
474 | 0 |
|
475 | 0 | // If we just inserted a root view, then update the RootViewManager |
476 | 0 | // on all view managers in the new subtree. |
477 | 0 |
|
478 | 0 | nsViewManager *vm = aChild->GetViewManager(); |
479 | 0 | if (vm->GetRootView() == aChild) |
480 | 0 | { |
481 | 0 | aChild->InvalidateHierarchy(); |
482 | 0 | } |
483 | 0 | } |
484 | 0 | } |
485 | | |
486 | | void nsView::RemoveChild(nsView *child) |
487 | 0 | { |
488 | 0 | MOZ_ASSERT(nullptr != child, "null ptr"); |
489 | 0 |
|
490 | 0 | if (nullptr != child) |
491 | 0 | { |
492 | 0 | nsView* prevKid = nullptr; |
493 | 0 | nsView* kid = mFirstChild; |
494 | 0 | DebugOnly<bool> found = false; |
495 | 0 | while (nullptr != kid) { |
496 | 0 | if (kid == child) { |
497 | 0 | if (nullptr != prevKid) { |
498 | 0 | prevKid->SetNextSibling(kid->GetNextSibling()); |
499 | 0 | } else { |
500 | 0 | mFirstChild = kid->GetNextSibling(); |
501 | 0 | } |
502 | 0 | child->SetParent(nullptr); |
503 | 0 | found = true; |
504 | 0 | break; |
505 | 0 | } |
506 | 0 | prevKid = kid; |
507 | 0 | kid = kid->GetNextSibling(); |
508 | 0 | } |
509 | 0 | NS_ASSERTION(found, "tried to remove non child"); |
510 | 0 |
|
511 | 0 | // If we just removed a root view, then update the RootViewManager |
512 | 0 | // on all view managers in the removed subtree. |
513 | 0 |
|
514 | 0 | nsViewManager *vm = child->GetViewManager(); |
515 | 0 | if (vm->GetRootView() == child) |
516 | 0 | { |
517 | 0 | child->InvalidateHierarchy(); |
518 | 0 | } |
519 | 0 | } |
520 | 0 | } |
521 | | |
522 | | // Native widgets ultimately just can't deal with the awesome power of |
523 | | // CSS2 z-index. However, we set the z-index on the widget anyway |
524 | | // because in many simple common cases the widgets do end up in the |
525 | | // right order. We set each widget's z-index to the z-index of the |
526 | | // nearest ancestor that has non-auto z-index. |
527 | | static void UpdateNativeWidgetZIndexes(nsView* aView, int32_t aZIndex) |
528 | 0 | { |
529 | 0 | if (aView->HasWidget()) { |
530 | 0 | nsIWidget* widget = aView->GetWidget(); |
531 | 0 | if (widget->GetZIndex() != aZIndex) { |
532 | 0 | widget->SetZIndex(aZIndex); |
533 | 0 | } |
534 | 0 | } else { |
535 | 0 | for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) { |
536 | 0 | if (v->GetZIndexIsAuto()) { |
537 | 0 | UpdateNativeWidgetZIndexes(v, aZIndex); |
538 | 0 | } |
539 | 0 | } |
540 | 0 | } |
541 | 0 | } |
542 | | |
543 | | static int32_t FindNonAutoZIndex(nsView* aView) |
544 | 0 | { |
545 | 0 | while (aView) { |
546 | 0 | if (!aView->GetZIndexIsAuto()) { |
547 | 0 | return aView->GetZIndex(); |
548 | 0 | } |
549 | 0 | aView = aView->GetParent(); |
550 | 0 | } |
551 | 0 | return 0; |
552 | 0 | } |
553 | | |
554 | | struct DefaultWidgetInitData : public nsWidgetInitData { |
555 | | DefaultWidgetInitData() : nsWidgetInitData() |
556 | 0 | { |
557 | 0 | mWindowType = eWindowType_child; |
558 | 0 | clipChildren = true; |
559 | 0 | clipSiblings = true; |
560 | 0 | } |
561 | | }; |
562 | | |
563 | | nsresult nsView::CreateWidget(nsWidgetInitData *aWidgetInitData, |
564 | | bool aEnableDragDrop, |
565 | | bool aResetVisibility) |
566 | 0 | { |
567 | 0 | AssertNoWindow(); |
568 | 0 | MOZ_ASSERT(!aWidgetInitData || |
569 | 0 | aWidgetInitData->mWindowType != eWindowType_popup, |
570 | 0 | "Use CreateWidgetForPopup"); |
571 | 0 |
|
572 | 0 | DefaultWidgetInitData defaultInitData; |
573 | 0 | bool initDataPassedIn = !!aWidgetInitData; |
574 | 0 | aWidgetInitData = aWidgetInitData ? aWidgetInitData : &defaultInitData; |
575 | 0 | defaultInitData.mListenForResizes = |
576 | 0 | (!initDataPassedIn && GetParent() && |
577 | 0 | GetParent()->GetViewManager() != mViewManager); |
578 | 0 |
|
579 | 0 | LayoutDeviceIntRect trect = CalcWidgetBounds(aWidgetInitData->mWindowType); |
580 | 0 |
|
581 | 0 | nsIWidget* parentWidget = |
582 | 0 | GetParent() ? GetParent()->GetNearestWidget(nullptr) : nullptr; |
583 | 0 | if (!parentWidget) { |
584 | 0 | NS_ERROR("nsView::CreateWidget without suitable parent widget??"); |
585 | 0 | return NS_ERROR_FAILURE; |
586 | 0 | } |
587 | 0 |
|
588 | 0 | // XXX: using aForceUseIWidgetParent=true to preserve previous |
589 | 0 | // semantics. It's not clear that it's actually needed. |
590 | 0 | mWindow = parentWidget->CreateChild(trect, aWidgetInitData, true); |
591 | 0 | if (!mWindow) { |
592 | 0 | return NS_ERROR_FAILURE; |
593 | 0 | } |
594 | 0 | |
595 | 0 | InitializeWindow(aEnableDragDrop, aResetVisibility); |
596 | 0 |
|
597 | 0 | return NS_OK; |
598 | 0 | } |
599 | | |
600 | | nsresult nsView::CreateWidgetForParent(nsIWidget* aParentWidget, |
601 | | nsWidgetInitData *aWidgetInitData, |
602 | | bool aEnableDragDrop, |
603 | | bool aResetVisibility) |
604 | 0 | { |
605 | 0 | AssertNoWindow(); |
606 | 0 | MOZ_ASSERT(!aWidgetInitData || |
607 | 0 | aWidgetInitData->mWindowType != eWindowType_popup, |
608 | 0 | "Use CreateWidgetForPopup"); |
609 | 0 | MOZ_ASSERT(aParentWidget, "Parent widget required"); |
610 | 0 |
|
611 | 0 | DefaultWidgetInitData defaultInitData; |
612 | 0 | aWidgetInitData = aWidgetInitData ? aWidgetInitData : &defaultInitData; |
613 | 0 |
|
614 | 0 | LayoutDeviceIntRect trect = CalcWidgetBounds(aWidgetInitData->mWindowType); |
615 | 0 |
|
616 | 0 | mWindow = aParentWidget->CreateChild(trect, aWidgetInitData); |
617 | 0 | if (!mWindow) { |
618 | 0 | return NS_ERROR_FAILURE; |
619 | 0 | } |
620 | 0 | |
621 | 0 | InitializeWindow(aEnableDragDrop, aResetVisibility); |
622 | 0 |
|
623 | 0 | return NS_OK; |
624 | 0 | } |
625 | | |
626 | | nsresult nsView::CreateWidgetForPopup(nsWidgetInitData *aWidgetInitData, |
627 | | nsIWidget* aParentWidget, |
628 | | bool aEnableDragDrop, |
629 | | bool aResetVisibility) |
630 | 0 | { |
631 | 0 | AssertNoWindow(); |
632 | 0 | MOZ_ASSERT(aWidgetInitData, "Widget init data required"); |
633 | 0 | MOZ_ASSERT(aWidgetInitData->mWindowType == eWindowType_popup, |
634 | 0 | "Use one of the other CreateWidget methods"); |
635 | 0 |
|
636 | 0 | LayoutDeviceIntRect trect = CalcWidgetBounds(aWidgetInitData->mWindowType); |
637 | 0 |
|
638 | 0 | // XXX/cjones: having these two separate creation cases seems ... um |
639 | 0 | // ... unnecessary, but it's the way the old code did it. Please |
640 | 0 | // unify them by first finding a suitable parent nsIWidget, then |
641 | 0 | // getting rid of aForceUseIWidgetParent. |
642 | 0 | if (aParentWidget) { |
643 | 0 | // XXX: using aForceUseIWidgetParent=true to preserve previous |
644 | 0 | // semantics. It's not clear that it's actually needed. |
645 | 0 | mWindow = aParentWidget->CreateChild(trect, aWidgetInitData, true); |
646 | 0 | } |
647 | 0 | else { |
648 | 0 | nsIWidget* nearestParent = GetParent() ? GetParent()->GetNearestWidget(nullptr) |
649 | 0 | : nullptr; |
650 | 0 | if (!nearestParent) { |
651 | 0 | // Without a parent, we can't make a popup. This can happen |
652 | 0 | // when printing |
653 | 0 | return NS_ERROR_FAILURE; |
654 | 0 | } |
655 | 0 | |
656 | 0 | mWindow = nearestParent->CreateChild(trect, aWidgetInitData); |
657 | 0 | } |
658 | 0 | if (!mWindow) { |
659 | 0 | return NS_ERROR_FAILURE; |
660 | 0 | } |
661 | 0 | |
662 | 0 | InitializeWindow(aEnableDragDrop, aResetVisibility); |
663 | 0 |
|
664 | 0 | return NS_OK; |
665 | 0 | } |
666 | | |
667 | | void |
668 | | nsView::InitializeWindow(bool aEnableDragDrop, bool aResetVisibility) |
669 | 0 | { |
670 | 0 | MOZ_ASSERT(mWindow, "Must have a window to initialize"); |
671 | 0 |
|
672 | 0 | mWindow->SetWidgetListener(this); |
673 | 0 |
|
674 | 0 | if (aEnableDragDrop) { |
675 | 0 | mWindow->EnableDragDrop(true); |
676 | 0 | } |
677 | 0 |
|
678 | 0 | // propagate the z-index to the widget. |
679 | 0 | UpdateNativeWidgetZIndexes(this, FindNonAutoZIndex(this)); |
680 | 0 |
|
681 | 0 | //make sure visibility state is accurate |
682 | 0 |
|
683 | 0 | if (aResetVisibility) { |
684 | 0 | SetVisibility(GetVisibility()); |
685 | 0 | } |
686 | 0 | } |
687 | | |
688 | | void |
689 | | nsView::SetNeedsWindowPropertiesSync() |
690 | 0 | { |
691 | 0 | mNeedsWindowPropertiesSync = true; |
692 | 0 | if (mViewManager) { |
693 | 0 | mViewManager->PostPendingUpdate(); |
694 | 0 | } |
695 | 0 | } |
696 | | |
697 | | |
698 | | // Attach to a top level widget and start receiving mirrored events. |
699 | | nsresult nsView::AttachToTopLevelWidget(nsIWidget* aWidget) |
700 | 0 | { |
701 | 0 | MOZ_ASSERT(nullptr != aWidget, "null widget ptr"); |
702 | 0 |
|
703 | 0 | /// XXXjimm This is a temporary workaround to an issue w/document |
704 | 0 | // viewer (bug 513162). |
705 | 0 | nsIWidgetListener* listener = aWidget->GetAttachedWidgetListener(); |
706 | 0 | if (listener) { |
707 | 0 | nsView *oldView = listener->GetView(); |
708 | 0 | if (oldView) { |
709 | 0 | oldView->DetachFromTopLevelWidget(); |
710 | 0 | } |
711 | 0 | } |
712 | 0 |
|
713 | 0 | // Note, the previous device context will be released. Detaching |
714 | 0 | // will not restore the old one. |
715 | 0 | aWidget->AttachViewToTopLevel(!nsIWidget::UsePuppetWidgets()); |
716 | 0 |
|
717 | 0 | mWindow = aWidget; |
718 | 0 |
|
719 | 0 | mWindow->SetAttachedWidgetListener(this); |
720 | 0 | if (mWindow->WindowType() != eWindowType_invisible) { |
721 | 0 | nsresult rv = mWindow->AsyncEnableDragDrop(true); |
722 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
723 | 0 | } |
724 | 0 | mWidgetIsTopLevel = true; |
725 | 0 |
|
726 | 0 | // Refresh the view bounds |
727 | 0 | CalcWidgetBounds(mWindow->WindowType()); |
728 | 0 |
|
729 | 0 | return NS_OK; |
730 | 0 | } |
731 | | |
732 | | // Detach this view from an attached widget. |
733 | | nsresult nsView::DetachFromTopLevelWidget() |
734 | 0 | { |
735 | 0 | MOZ_ASSERT(mWidgetIsTopLevel, "Not attached currently!"); |
736 | 0 | MOZ_ASSERT(mWindow, "null mWindow for DetachFromTopLevelWidget!"); |
737 | 0 |
|
738 | 0 | mWindow->SetAttachedWidgetListener(nullptr); |
739 | 0 | nsIWidgetListener* listener = mWindow->GetPreviouslyAttachedWidgetListener(); |
740 | 0 |
|
741 | 0 | if (listener && listener->GetView()) { |
742 | 0 | // Ensure the listener doesn't think it's being used anymore |
743 | 0 | listener->GetView()->SetPreviousWidget(nullptr); |
744 | 0 | } |
745 | 0 |
|
746 | 0 | // If the new view's frame is paint suppressed then the window |
747 | 0 | // will want to use us instead until that's done |
748 | 0 | mWindow->SetPreviouslyAttachedWidgetListener(this); |
749 | 0 |
|
750 | 0 | mPreviousWindow = mWindow; |
751 | 0 | mWindow = nullptr; |
752 | 0 |
|
753 | 0 | mWidgetIsTopLevel = false; |
754 | 0 |
|
755 | 0 | return NS_OK; |
756 | 0 | } |
757 | | |
758 | | void nsView::SetZIndex(bool aAuto, int32_t aZIndex) |
759 | 0 | { |
760 | 0 | bool oldIsAuto = GetZIndexIsAuto(); |
761 | 0 | mVFlags = (mVFlags & ~NS_VIEW_FLAG_AUTO_ZINDEX) | (aAuto ? NS_VIEW_FLAG_AUTO_ZINDEX : 0); |
762 | 0 | mZIndex = aZIndex; |
763 | 0 |
|
764 | 0 | if (HasWidget() || !oldIsAuto || !aAuto) { |
765 | 0 | UpdateNativeWidgetZIndexes(this, FindNonAutoZIndex(this)); |
766 | 0 | } |
767 | 0 | } |
768 | | |
769 | | void nsView::AssertNoWindow() |
770 | 0 | { |
771 | 0 | // XXX: it would be nice to make this a strong assert |
772 | 0 | if (MOZ_UNLIKELY(mWindow)) { |
773 | 0 | NS_ERROR("We already have a window for this view? BAD"); |
774 | 0 | mWindow->SetWidgetListener(nullptr); |
775 | 0 | mWindow->Destroy(); |
776 | 0 | mWindow = nullptr; |
777 | 0 | } |
778 | 0 | } |
779 | | |
780 | | // |
781 | | // internal window creation functions |
782 | | // |
783 | | void nsView::AttachWidgetEventHandler(nsIWidget* aWidget) |
784 | 0 | { |
785 | | #ifdef DEBUG |
786 | | NS_ASSERTION(!aWidget->GetWidgetListener(), "Already have a widget listener"); |
787 | | #endif |
788 | |
|
789 | 0 | aWidget->SetWidgetListener(this); |
790 | 0 | } |
791 | | |
792 | | void nsView::DetachWidgetEventHandler(nsIWidget* aWidget) |
793 | 0 | { |
794 | 0 | NS_ASSERTION(!aWidget->GetWidgetListener() || |
795 | 0 | aWidget->GetWidgetListener()->GetView() == this, "Wrong view"); |
796 | 0 | aWidget->SetWidgetListener(nullptr); |
797 | 0 | } |
798 | | |
799 | | #ifdef DEBUG |
800 | | void nsView::List(FILE* out, int32_t aIndent) const |
801 | | { |
802 | | int32_t i; |
803 | | for (i = aIndent; --i >= 0; ) fputs(" ", out); |
804 | | fprintf(out, "%p ", (void*)this); |
805 | | if (nullptr != mWindow) { |
806 | | nscoord p2a = mViewManager->AppUnitsPerDevPixel(); |
807 | | LayoutDeviceIntRect rect = mWindow->GetClientBounds(); |
808 | | nsRect windowBounds = LayoutDeviceIntRect::ToAppUnits(rect, p2a); |
809 | | rect = mWindow->GetBounds(); |
810 | | nsRect nonclientBounds = LayoutDeviceIntRect::ToAppUnits(rect, p2a); |
811 | | nsrefcnt widgetRefCnt = mWindow.get()->AddRef() - 1; |
812 | | mWindow.get()->Release(); |
813 | | int32_t Z = mWindow->GetZIndex(); |
814 | | fprintf(out, "(widget=%p[%" PRIuPTR "] z=%d pos={%d,%d,%d,%d}) ", |
815 | | (void*)mWindow, widgetRefCnt, Z, |
816 | | nonclientBounds.X(), nonclientBounds.Y(), |
817 | | windowBounds.Width(), windowBounds.Height()); |
818 | | } |
819 | | nsRect brect = GetBounds(); |
820 | | fprintf(out, "{%d,%d,%d,%d}", |
821 | | brect.X(), brect.Y(), brect.Width(), brect.Height()); |
822 | | fprintf(out, " z=%d vis=%d frame=%p <\n", |
823 | | mZIndex, mVis, static_cast<void*>(mFrame)); |
824 | | for (nsView* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { |
825 | | NS_ASSERTION(kid->GetParent() == this, "incorrect parent"); |
826 | | kid->List(out, aIndent + 1); |
827 | | } |
828 | | for (i = aIndent; --i >= 0; ) fputs(" ", out); |
829 | | fputs(">\n", out); |
830 | | } |
831 | | #endif // DEBUG |
832 | | |
833 | | nsPoint nsView::GetOffsetTo(const nsView* aOther) const |
834 | 0 | { |
835 | 0 | return GetOffsetTo(aOther, GetViewManager()->AppUnitsPerDevPixel()); |
836 | 0 | } |
837 | | |
838 | | nsPoint nsView::GetOffsetTo(const nsView* aOther, const int32_t aAPD) const |
839 | 0 | { |
840 | 0 | MOZ_ASSERT(GetParent() || !aOther || aOther->GetParent() || this == aOther, |
841 | 0 | "caller of (outer) GetOffsetTo must not pass unrelated views"); |
842 | 0 | // We accumulate the final result in offset |
843 | 0 | nsPoint offset(0, 0); |
844 | 0 | // The offset currently accumulated at the current APD |
845 | 0 | nsPoint docOffset(0, 0); |
846 | 0 | const nsView* v = this; |
847 | 0 | nsViewManager* currVM = v->GetViewManager(); |
848 | 0 | int32_t currAPD = currVM->AppUnitsPerDevPixel(); |
849 | 0 | const nsView* root = nullptr; |
850 | 0 | for ( ; v != aOther && v; root = v, v = v->GetParent()) { |
851 | 0 | nsViewManager* newVM = v->GetViewManager(); |
852 | 0 | if (newVM != currVM) { |
853 | 0 | int32_t newAPD = newVM->AppUnitsPerDevPixel(); |
854 | 0 | if (newAPD != currAPD) { |
855 | 0 | offset += docOffset.ScaleToOtherAppUnits(currAPD, aAPD); |
856 | 0 | docOffset.x = docOffset.y = 0; |
857 | 0 | currAPD = newAPD; |
858 | 0 | } |
859 | 0 | currVM = newVM; |
860 | 0 | } |
861 | 0 | docOffset += v->GetPosition(); |
862 | 0 | } |
863 | 0 | offset += docOffset.ScaleToOtherAppUnits(currAPD, aAPD); |
864 | 0 |
|
865 | 0 | if (v != aOther) { |
866 | 0 | // Looks like aOther wasn't an ancestor of |this|. So now we have |
867 | 0 | // the root-VM-relative position of |this| in |offset|. Get the |
868 | 0 | // root-VM-relative position of aOther and subtract it. |
869 | 0 | nsPoint negOffset = aOther->GetOffsetTo(root, aAPD); |
870 | 0 | offset -= negOffset; |
871 | 0 | } |
872 | 0 |
|
873 | 0 | return offset; |
874 | 0 | } |
875 | | |
876 | | nsPoint nsView::GetOffsetToWidget(nsIWidget* aWidget) const |
877 | 0 | { |
878 | 0 | nsPoint pt; |
879 | 0 | // Get the view for widget |
880 | 0 | nsView* widgetView = GetViewFor(aWidget); |
881 | 0 | if (!widgetView) { |
882 | 0 | return pt; |
883 | 0 | } |
884 | 0 | |
885 | 0 | // Get the offset to the widget view in the widget view's APD |
886 | 0 | // We get the offset in the widget view's APD first and then convert to our |
887 | 0 | // APD afterwards so that we can include the widget view's ViewToWidgetOffset |
888 | 0 | // in the sum in its native APD, and then convert the whole thing to our APD |
889 | 0 | // so that we don't have to convert the APD of the relatively small |
890 | 0 | // ViewToWidgetOffset by itself with a potentially large relative rounding |
891 | 0 | // error. |
892 | 0 | pt = -widgetView->GetOffsetTo(this); |
893 | 0 | // Add in the offset to the widget. |
894 | 0 | pt += widgetView->ViewToWidgetOffset(); |
895 | 0 |
|
896 | 0 | // Convert to our appunits. |
897 | 0 | int32_t widgetAPD = widgetView->GetViewManager()->AppUnitsPerDevPixel(); |
898 | 0 | int32_t ourAPD = GetViewManager()->AppUnitsPerDevPixel(); |
899 | 0 | pt = pt.ScaleToOtherAppUnits(widgetAPD, ourAPD); |
900 | 0 | return pt; |
901 | 0 | } |
902 | | |
903 | | nsIWidget* nsView::GetNearestWidget(nsPoint* aOffset) const |
904 | 0 | { |
905 | 0 | return GetNearestWidget(aOffset, GetViewManager()->AppUnitsPerDevPixel()); |
906 | 0 | } |
907 | | |
908 | | nsIWidget* nsView::GetNearestWidget(nsPoint* aOffset, const int32_t aAPD) const |
909 | 0 | { |
910 | 0 | // aOffset is based on the view's position, which ignores any chrome on |
911 | 0 | // attached parent widgets. |
912 | 0 |
|
913 | 0 | // We accumulate the final result in pt |
914 | 0 | nsPoint pt(0, 0); |
915 | 0 | // The offset currently accumulated at the current APD |
916 | 0 | nsPoint docPt(0,0); |
917 | 0 | const nsView* v = this; |
918 | 0 | nsViewManager* currVM = v->GetViewManager(); |
919 | 0 | int32_t currAPD = currVM->AppUnitsPerDevPixel(); |
920 | 0 | for ( ; v && !v->HasWidget(); v = v->GetParent()) { |
921 | 0 | nsViewManager* newVM = v->GetViewManager(); |
922 | 0 | if (newVM != currVM) { |
923 | 0 | int32_t newAPD = newVM->AppUnitsPerDevPixel(); |
924 | 0 | if (newAPD != currAPD) { |
925 | 0 | pt += docPt.ScaleToOtherAppUnits(currAPD, aAPD); |
926 | 0 | docPt.x = docPt.y = 0; |
927 | 0 | currAPD = newAPD; |
928 | 0 | } |
929 | 0 | currVM = newVM; |
930 | 0 | } |
931 | 0 | docPt += v->GetPosition(); |
932 | 0 | } |
933 | 0 | if (!v) { |
934 | 0 | if (aOffset) { |
935 | 0 | pt += docPt.ScaleToOtherAppUnits(currAPD, aAPD); |
936 | 0 | *aOffset = pt; |
937 | 0 | } |
938 | 0 | return nullptr; |
939 | 0 | } |
940 | 0 |
|
941 | 0 | // pt is now the offset from v's origin to this view's origin. |
942 | 0 | // We add the ViewToWidgetOffset to get the offset to the widget. |
943 | 0 | if (aOffset) { |
944 | 0 | docPt += v->ViewToWidgetOffset(); |
945 | 0 | pt += docPt.ScaleToOtherAppUnits(currAPD, aAPD); |
946 | 0 | *aOffset = pt; |
947 | 0 | } |
948 | 0 | return v->GetWidget(); |
949 | 0 | } |
950 | | |
951 | | bool nsView::IsRoot() const |
952 | 0 | { |
953 | 0 | NS_ASSERTION(mViewManager != nullptr," View manager is null in nsView::IsRoot()"); |
954 | 0 | return mViewManager->GetRootView() == this; |
955 | 0 | } |
956 | | |
957 | | nsRect |
958 | | nsView::GetBoundsInParentUnits() const |
959 | 0 | { |
960 | 0 | nsView* parent = GetParent(); |
961 | 0 | nsViewManager* VM = GetViewManager(); |
962 | 0 | if (this != VM->GetRootView() || !parent) { |
963 | 0 | return mDimBounds; |
964 | 0 | } |
965 | 0 | int32_t ourAPD = VM->AppUnitsPerDevPixel(); |
966 | 0 | int32_t parentAPD = parent->GetViewManager()->AppUnitsPerDevPixel(); |
967 | 0 | return mDimBounds.ScaleToOtherAppUnitsRoundOut(ourAPD, parentAPD); |
968 | 0 | } |
969 | | |
970 | | nsPoint |
971 | | nsView::ConvertFromParentCoords(nsPoint aPt) const |
972 | 0 | { |
973 | 0 | const nsView* parent = GetParent(); |
974 | 0 | if (parent) { |
975 | 0 | aPt = aPt.ScaleToOtherAppUnits( |
976 | 0 | parent->GetViewManager()->AppUnitsPerDevPixel(), |
977 | 0 | GetViewManager()->AppUnitsPerDevPixel()); |
978 | 0 | } |
979 | 0 | aPt -= GetPosition(); |
980 | 0 | return aPt; |
981 | 0 | } |
982 | | |
983 | | static bool |
984 | | IsPopupWidget(nsIWidget* aWidget) |
985 | 0 | { |
986 | 0 | return (aWidget->WindowType() == eWindowType_popup); |
987 | 0 | } |
988 | | |
989 | | nsIPresShell* |
990 | | nsView::GetPresShell() |
991 | 0 | { |
992 | 0 | return GetViewManager()->GetPresShell(); |
993 | 0 | } |
994 | | |
995 | | bool |
996 | | nsView::WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y) |
997 | 0 | { |
998 | 0 | nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); |
999 | 0 | if (pm && IsPopupWidget(aWidget)) { |
1000 | 0 | pm->PopupMoved(mFrame, nsIntPoint(x, y)); |
1001 | 0 | return true; |
1002 | 0 | } |
1003 | 0 | |
1004 | 0 | return false; |
1005 | 0 | } |
1006 | | |
1007 | | bool |
1008 | | nsView::WindowResized(nsIWidget* aWidget, int32_t aWidth, int32_t aHeight) |
1009 | 0 | { |
1010 | 0 | // The root view may not be set if this is the resize associated with |
1011 | 0 | // window creation |
1012 | 0 | SetForcedRepaint(true); |
1013 | 0 | if (this == mViewManager->GetRootView()) { |
1014 | 0 | RefPtr<nsDeviceContext> devContext = mViewManager->GetDeviceContext(); |
1015 | 0 | // ensure DPI is up-to-date, in case of window being opened and sized |
1016 | 0 | // on a non-default-dpi display (bug 829963) |
1017 | 0 | devContext->CheckDPIChange(); |
1018 | 0 | int32_t p2a = devContext->AppUnitsPerDevPixel(); |
1019 | 0 | mViewManager->SetWindowDimensions(NSIntPixelsToAppUnits(aWidth, p2a), |
1020 | 0 | NSIntPixelsToAppUnits(aHeight, p2a)); |
1021 | 0 |
|
1022 | 0 | nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); |
1023 | 0 | if (pm) { |
1024 | 0 | nsIPresShell* presShell = mViewManager->GetPresShell(); |
1025 | 0 | if (presShell && presShell->GetDocument()) { |
1026 | 0 | pm->AdjustPopupsOnWindowChange(presShell); |
1027 | 0 | } |
1028 | 0 | } |
1029 | 0 |
|
1030 | 0 | return true; |
1031 | 0 | } |
1032 | 0 | if (IsPopupWidget(aWidget)) { |
1033 | 0 | nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); |
1034 | 0 | if (pm) { |
1035 | 0 | pm->PopupResized(mFrame, LayoutDeviceIntSize(aWidth, aHeight)); |
1036 | 0 | return true; |
1037 | 0 | } |
1038 | 0 | } |
1039 | 0 | |
1040 | 0 | return false; |
1041 | 0 | } |
1042 | | |
1043 | | bool |
1044 | | nsView::RequestWindowClose(nsIWidget* aWidget) |
1045 | 0 | { |
1046 | 0 | if (mFrame && IsPopupWidget(aWidget) && mFrame->IsMenuPopupFrame()) { |
1047 | 0 | nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); |
1048 | 0 | if (pm) { |
1049 | 0 | pm->HidePopup(mFrame->GetContent(), false, true, false, false); |
1050 | 0 | return true; |
1051 | 0 | } |
1052 | 0 | } |
1053 | 0 | |
1054 | 0 | return false; |
1055 | 0 | } |
1056 | | |
1057 | | void |
1058 | | nsView::WillPaintWindow(nsIWidget* aWidget) |
1059 | 0 | { |
1060 | 0 | RefPtr<nsViewManager> vm = mViewManager; |
1061 | 0 | vm->WillPaintWindow(aWidget); |
1062 | 0 | } |
1063 | | |
1064 | | bool |
1065 | | nsView::PaintWindow(nsIWidget* aWidget, LayoutDeviceIntRegion aRegion) |
1066 | 0 | { |
1067 | 0 | NS_ASSERTION(this == nsView::GetViewFor(aWidget), "wrong view for widget?"); |
1068 | 0 |
|
1069 | 0 | RefPtr<nsViewManager> vm = mViewManager; |
1070 | 0 | bool result = vm->PaintWindow(aWidget, aRegion); |
1071 | 0 | return result; |
1072 | 0 | } |
1073 | | |
1074 | | void |
1075 | | nsView::DidPaintWindow() |
1076 | 0 | { |
1077 | 0 | RefPtr<nsViewManager> vm = mViewManager; |
1078 | 0 | vm->DidPaintWindow(); |
1079 | 0 | } |
1080 | | |
1081 | | void |
1082 | | nsView::DidCompositeWindow(mozilla::layers::TransactionId aTransactionId, |
1083 | | const TimeStamp& aCompositeStart, |
1084 | | const TimeStamp& aCompositeEnd) |
1085 | 0 | { |
1086 | 0 | nsIPresShell* presShell = mViewManager->GetPresShell(); |
1087 | 0 | if (presShell) { |
1088 | 0 | nsAutoScriptBlocker scriptBlocker; |
1089 | 0 |
|
1090 | 0 | nsPresContext* context = presShell->GetPresContext(); |
1091 | 0 | nsRootPresContext* rootContext = context->GetRootPresContext(); |
1092 | 0 | if (rootContext) { |
1093 | 0 | rootContext->NotifyDidPaintForSubtree(aTransactionId, aCompositeEnd); |
1094 | 0 | } |
1095 | 0 |
|
1096 | 0 | // If the two timestamps are identical, this was likely a fake composite |
1097 | 0 | // event which wouldn't be terribly useful to display. |
1098 | 0 | if (aCompositeStart == aCompositeEnd) { |
1099 | 0 | return; |
1100 | 0 | } |
1101 | 0 | |
1102 | 0 | nsIDocShell* docShell = context->GetDocShell(); |
1103 | 0 | RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get(); |
1104 | 0 |
|
1105 | 0 | if (timelines && timelines->HasConsumer(docShell)) { |
1106 | 0 | timelines->AddMarkerForDocShell(docShell, |
1107 | 0 | MakeUnique<CompositeTimelineMarker>(aCompositeStart, MarkerTracingType::START)); |
1108 | 0 | timelines->AddMarkerForDocShell(docShell, |
1109 | 0 | MakeUnique<CompositeTimelineMarker>(aCompositeEnd, MarkerTracingType::END)); |
1110 | 0 | } |
1111 | 0 | } |
1112 | 0 | } |
1113 | | |
1114 | | void |
1115 | | nsView::RequestRepaint() |
1116 | 0 | { |
1117 | 0 | nsIPresShell* presShell = mViewManager->GetPresShell(); |
1118 | 0 | if (presShell) { |
1119 | 0 | presShell->ScheduleViewManagerFlush(); |
1120 | 0 | } |
1121 | 0 | } |
1122 | | |
1123 | | nsEventStatus |
1124 | | nsView::HandleEvent(WidgetGUIEvent* aEvent, |
1125 | | bool aUseAttachedEvents) |
1126 | 0 | { |
1127 | 0 | MOZ_ASSERT(nullptr != aEvent->mWidget, "null widget ptr"); |
1128 | 0 |
|
1129 | 0 | nsEventStatus result = nsEventStatus_eIgnore; |
1130 | 0 | nsView* view; |
1131 | 0 | if (aUseAttachedEvents) { |
1132 | 0 | nsIWidgetListener* listener = aEvent->mWidget->GetAttachedWidgetListener(); |
1133 | 0 | view = listener ? listener->GetView() : nullptr; |
1134 | 0 | } |
1135 | 0 | else { |
1136 | 0 | view = GetViewFor(aEvent->mWidget); |
1137 | 0 | } |
1138 | 0 |
|
1139 | 0 | if (view) { |
1140 | 0 | RefPtr<nsViewManager> vm = view->GetViewManager(); |
1141 | 0 | vm->DispatchEvent(aEvent, view, &result); |
1142 | 0 | } |
1143 | 0 |
|
1144 | 0 | return result; |
1145 | 0 | } |
1146 | | |
1147 | | bool |
1148 | | nsView::IsPrimaryFramePaintSuppressed() |
1149 | 0 | { |
1150 | 0 | return sShowPreviousPage && mFrame && mFrame->PresShell()->IsPaintingSuppressed(); |
1151 | 0 | } |