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