1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/view/src/nsView.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1101 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsView.h" 1.10 + 1.11 +#include "mozilla/Attributes.h" 1.12 +#include "mozilla/BasicEvents.h" 1.13 +#include "mozilla/DebugOnly.h" 1.14 +#include "mozilla/IntegerPrintfMacros.h" 1.15 +#include "mozilla/Likely.h" 1.16 +#include "mozilla/Poison.h" 1.17 +#include "nsIWidget.h" 1.18 +#include "nsViewManager.h" 1.19 +#include "nsIFrame.h" 1.20 +#include "nsPresArena.h" 1.21 +#include "nsXULPopupManager.h" 1.22 +#include "nsIWidgetListener.h" 1.23 +#include "nsContentUtils.h" // for nsAutoScriptBlocker 1.24 + 1.25 +using namespace mozilla; 1.26 + 1.27 +nsView::nsView(nsViewManager* aViewManager, nsViewVisibility aVisibility) 1.28 +{ 1.29 + MOZ_COUNT_CTOR(nsView); 1.30 + 1.31 + mVis = aVisibility; 1.32 + // Views should be transparent by default. Not being transparent is 1.33 + // a promise that the view will paint all its pixels opaquely. Views 1.34 + // should make this promise explicitly by calling 1.35 + // SetViewContentTransparency. 1.36 + mVFlags = 0; 1.37 + mViewManager = aViewManager; 1.38 + mDirtyRegion = nullptr; 1.39 + mWidgetIsTopLevel = false; 1.40 +} 1.41 + 1.42 +void nsView::DropMouseGrabbing() 1.43 +{ 1.44 + nsIPresShell* presShell = mViewManager->GetPresShell(); 1.45 + if (presShell) 1.46 + presShell->ClearMouseCaptureOnView(this); 1.47 +} 1.48 + 1.49 +nsView::~nsView() 1.50 +{ 1.51 + MOZ_COUNT_DTOR(nsView); 1.52 + 1.53 + while (GetFirstChild()) 1.54 + { 1.55 + nsView* child = GetFirstChild(); 1.56 + if (child->GetViewManager() == mViewManager) { 1.57 + child->Destroy(); 1.58 + } else { 1.59 + // just unhook it. Someone else will want to destroy this. 1.60 + RemoveChild(child); 1.61 + } 1.62 + } 1.63 + 1.64 + if (mViewManager) 1.65 + { 1.66 + DropMouseGrabbing(); 1.67 + 1.68 + nsView *rootView = mViewManager->GetRootView(); 1.69 + 1.70 + if (rootView) 1.71 + { 1.72 + // Root views can have parents! 1.73 + if (mParent) 1.74 + { 1.75 + mViewManager->RemoveChild(this); 1.76 + } 1.77 + 1.78 + if (rootView == this) 1.79 + { 1.80 + // Inform the view manager that the root view has gone away... 1.81 + mViewManager->SetRootView(nullptr); 1.82 + } 1.83 + } 1.84 + else if (mParent) 1.85 + { 1.86 + mParent->RemoveChild(this); 1.87 + } 1.88 + 1.89 + mViewManager = nullptr; 1.90 + } 1.91 + else if (mParent) 1.92 + { 1.93 + mParent->RemoveChild(this); 1.94 + } 1.95 + 1.96 + // Destroy and release the widget 1.97 + DestroyWidget(); 1.98 + 1.99 + delete mDirtyRegion; 1.100 +} 1.101 + 1.102 +class DestroyWidgetRunnable : public nsRunnable { 1.103 +public: 1.104 + NS_DECL_NSIRUNNABLE 1.105 + 1.106 + explicit DestroyWidgetRunnable(nsIWidget* aWidget) : mWidget(aWidget) {} 1.107 + 1.108 +private: 1.109 + nsCOMPtr<nsIWidget> mWidget; 1.110 +}; 1.111 + 1.112 +NS_IMETHODIMP DestroyWidgetRunnable::Run() 1.113 +{ 1.114 + mWidget->Destroy(); 1.115 + mWidget = nullptr; 1.116 + return NS_OK; 1.117 +} 1.118 + 1.119 + 1.120 +void nsView::DestroyWidget() 1.121 +{ 1.122 + if (mWindow) 1.123 + { 1.124 + // If we are not attached to a base window, we're going to tear down our 1.125 + // widget here. However, if we're attached to somebody elses widget, we 1.126 + // want to leave the widget alone: don't reset the client data or call 1.127 + // Destroy. Just clear our event view ptr and free our reference to it. 1.128 + if (mWidgetIsTopLevel) { 1.129 + mWindow->SetAttachedWidgetListener(nullptr); 1.130 + } 1.131 + else { 1.132 + mWindow->SetWidgetListener(nullptr); 1.133 + 1.134 + nsCOMPtr<nsIRunnable> widgetDestroyer = 1.135 + new DestroyWidgetRunnable(mWindow); 1.136 + 1.137 + NS_DispatchToMainThread(widgetDestroyer); 1.138 + } 1.139 + 1.140 + NS_RELEASE(mWindow); 1.141 + } 1.142 +} 1.143 + 1.144 +nsView* nsView::GetViewFor(nsIWidget* aWidget) 1.145 +{ 1.146 + NS_PRECONDITION(nullptr != aWidget, "null widget ptr"); 1.147 + 1.148 + nsIWidgetListener* listener = aWidget->GetWidgetListener(); 1.149 + if (listener) { 1.150 + nsView* view = listener->GetView(); 1.151 + if (view) 1.152 + return view; 1.153 + } 1.154 + 1.155 + listener = aWidget->GetAttachedWidgetListener(); 1.156 + return listener ? listener->GetView() : nullptr; 1.157 +} 1.158 + 1.159 +void nsView::Destroy() 1.160 +{ 1.161 + this->~nsView(); 1.162 + mozWritePoison(this, sizeof(*this)); 1.163 + nsView::operator delete(this); 1.164 +} 1.165 + 1.166 +void nsView::SetPosition(nscoord aX, nscoord aY) 1.167 +{ 1.168 + mDimBounds.x += aX - mPosX; 1.169 + mDimBounds.y += aY - mPosY; 1.170 + mPosX = aX; 1.171 + mPosY = aY; 1.172 + 1.173 + NS_ASSERTION(GetParent() || (aX == 0 && aY == 0), 1.174 + "Don't try to move the root widget to something non-zero"); 1.175 + 1.176 + ResetWidgetBounds(true, false); 1.177 +} 1.178 + 1.179 +void nsView::ResetWidgetBounds(bool aRecurse, bool aForceSync) 1.180 +{ 1.181 + if (mWindow) { 1.182 + if (!aForceSync) { 1.183 + // Don't change widget geometry synchronously, since that can 1.184 + // cause synchronous painting. 1.185 + mViewManager->PostPendingUpdate(); 1.186 + } else { 1.187 + DoResetWidgetBounds(false, true); 1.188 + } 1.189 + return; 1.190 + } 1.191 + 1.192 + if (aRecurse) { 1.193 + // reposition any widgets under this view 1.194 + for (nsView* v = GetFirstChild(); v; v = v->GetNextSibling()) { 1.195 + v->ResetWidgetBounds(true, aForceSync); 1.196 + } 1.197 + } 1.198 +} 1.199 + 1.200 +bool nsView::IsEffectivelyVisible() 1.201 +{ 1.202 + for (nsView* v = this; v; v = v->mParent) { 1.203 + if (v->GetVisibility() == nsViewVisibility_kHide) 1.204 + return false; 1.205 + } 1.206 + return true; 1.207 +} 1.208 + 1.209 +nsIntRect nsView::CalcWidgetBounds(nsWindowType aType) 1.210 +{ 1.211 + int32_t p2a = mViewManager->AppUnitsPerDevPixel(); 1.212 + 1.213 + nsRect viewBounds(mDimBounds); 1.214 + 1.215 + nsView* parent = GetParent(); 1.216 + nsIWidget* parentWidget = nullptr; 1.217 + if (parent) { 1.218 + nsPoint offset; 1.219 + parentWidget = parent->GetNearestWidget(&offset, p2a); 1.220 + // make viewBounds be relative to the parent widget, in appunits 1.221 + viewBounds += offset; 1.222 + 1.223 + if (parentWidget && aType == eWindowType_popup && 1.224 + IsEffectivelyVisible()) { 1.225 + // put offset into screen coordinates. (based on client area origin) 1.226 + nsIntPoint screenPoint = parentWidget->WidgetToScreenOffset(); 1.227 + viewBounds += nsPoint(NSIntPixelsToAppUnits(screenPoint.x, p2a), 1.228 + NSIntPixelsToAppUnits(screenPoint.y, p2a)); 1.229 + } 1.230 + } 1.231 + 1.232 + // Compute widget bounds in device pixels 1.233 + nsIntRect newBounds = viewBounds.ToNearestPixels(p2a); 1.234 + 1.235 +#ifdef XP_MACOSX 1.236 + // cocoa rounds widget coordinates to the nearest global "display pixel" 1.237 + // integer value. So we avoid fractional display pixel values by rounding 1.238 + // to the nearest value that won't yield a fractional display pixel. 1.239 + nsIWidget* widget = parentWidget ? parentWidget : mWindow; 1.240 + uint32_t round; 1.241 + if (aType == eWindowType_popup && widget && 1.242 + ((round = widget->RoundsWidgetCoordinatesTo()) > 1)) { 1.243 + nsIntSize pixelRoundedSize = newBounds.Size(); 1.244 + // round the top left and bottom right to the nearest round pixel 1.245 + newBounds.x = NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.x, p2a) / round) * round; 1.246 + newBounds.y = NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.y, p2a) / round) * round; 1.247 + newBounds.width = 1.248 + NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.XMost(), p2a) / round) * round - newBounds.x; 1.249 + newBounds.height = 1.250 + NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.YMost(), p2a) / round) * round - newBounds.y; 1.251 + // but if that makes the widget larger then our frame may not paint the 1.252 + // extra pixels, so reduce the size to the nearest round value 1.253 + if (newBounds.width > pixelRoundedSize.width) { 1.254 + newBounds.width -= round; 1.255 + } 1.256 + if (newBounds.height > pixelRoundedSize.height) { 1.257 + newBounds.height -= round; 1.258 + } 1.259 + } 1.260 +#endif 1.261 + 1.262 + // Compute where the top-left of our widget ended up relative to the parent 1.263 + // widget, in appunits. 1.264 + nsPoint roundedOffset(NSIntPixelsToAppUnits(newBounds.x, p2a), 1.265 + NSIntPixelsToAppUnits(newBounds.y, p2a)); 1.266 + 1.267 + // mViewToWidgetOffset is added to coordinates relative to the view origin 1.268 + // to get coordinates relative to the widget. 1.269 + // The view origin, relative to the parent widget, is at 1.270 + // (mPosX,mPosY) - mDimBounds.TopLeft() + viewBounds.TopLeft(). 1.271 + // Our widget, relative to the parent widget, is roundedOffset. 1.272 + mViewToWidgetOffset = nsPoint(mPosX, mPosY) 1.273 + - mDimBounds.TopLeft() + viewBounds.TopLeft() - roundedOffset; 1.274 + 1.275 + return newBounds; 1.276 +} 1.277 + 1.278 +void nsView::DoResetWidgetBounds(bool aMoveOnly, 1.279 + bool aInvalidateChangedSize) { 1.280 + // The geometry of a root view's widget is controlled externally, 1.281 + // NOT by sizing or positioning the view 1.282 + if (mViewManager->GetRootView() == this) { 1.283 + return; 1.284 + } 1.285 + 1.286 + NS_PRECONDITION(mWindow, "Why was this called??"); 1.287 + 1.288 + // Hold this ref to make sure it stays alive. 1.289 + nsCOMPtr<nsIWidget> widget = mWindow; 1.290 + 1.291 + // Stash a copy of these and use them so we can handle this being deleted (say 1.292 + // from sync painting/flushing from Show/Move/Resize on the widget). 1.293 + nsIntRect newBounds; 1.294 + nsRefPtr<nsDeviceContext> dx = mViewManager->GetDeviceContext(); 1.295 + 1.296 + nsWindowType type = widget->WindowType(); 1.297 + 1.298 + nsIntRect curBounds; 1.299 + widget->GetClientBounds(curBounds); 1.300 + bool invisiblePopup = type == eWindowType_popup && 1.301 + ((curBounds.IsEmpty() && mDimBounds.IsEmpty()) || 1.302 + mVis == nsViewVisibility_kHide); 1.303 + 1.304 + if (invisiblePopup) { 1.305 + // We're going to hit the early exit below, avoid calling CalcWidgetBounds. 1.306 + } else { 1.307 + newBounds = CalcWidgetBounds(type); 1.308 + } 1.309 + 1.310 + bool curVisibility = widget->IsVisible(); 1.311 + bool newVisibility = IsEffectivelyVisible(); 1.312 + if (curVisibility && !newVisibility) { 1.313 + widget->Show(false); 1.314 + } 1.315 + 1.316 + if (invisiblePopup) { 1.317 + // Don't manipulate empty or hidden popup widgets. For example there's no 1.318 + // point moving hidden comboboxes around, or doing X server roundtrips 1.319 + // to compute their true screen position. This could mean that WidgetToScreen 1.320 + // operations on these widgets don't return up-to-date values, but popup 1.321 + // positions aren't reliable anyway because of correction to be on or off-screen. 1.322 + return; 1.323 + } 1.324 + 1.325 + bool changedPos = curBounds.TopLeft() != newBounds.TopLeft(); 1.326 + bool changedSize = curBounds.Size() != newBounds.Size(); 1.327 + 1.328 + // Child views are never attached to top level widgets, this is safe. 1.329 + 1.330 + // Coordinates are converted to display pixels for window Move/Resize APIs, 1.331 + // because of the potential for device-pixel coordinate spaces for mixed 1.332 + // hidpi/lodpi screens to overlap each other and result in bad placement 1.333 + // (bug 814434). 1.334 + double invScale; 1.335 + 1.336 + // Bug 861270: for correct widget manipulation at arbitrary scale factors, 1.337 + // prefer to base scaling on widget->GetDefaultScale(). But only do this if 1.338 + // it matches the view manager's device context scale after allowing for the 1.339 + // quantization to app units, because of OS X multiscreen issues (where the 1.340 + // only two scales are 1.0 or 2.0, and so the quantization doesn't actually 1.341 + // cause problems anyhow). 1.342 + // In the case of a mismatch, fall back to scaling based on the dev context's 1.343 + // unscaledAppUnitsPerDevPixel value. On platforms where the device-pixel 1.344 + // scale is uniform across all displays (currently all except OS X), we'll 1.345 + // always use the precise value from mWindow->GetDefaultScale here. 1.346 + CSSToLayoutDeviceScale scale = widget->GetDefaultScale(); 1.347 + if (NSToIntRound(60.0 / scale.scale) == dx->UnscaledAppUnitsPerDevPixel()) { 1.348 + invScale = 1.0 / scale.scale; 1.349 + } else { 1.350 + invScale = dx->UnscaledAppUnitsPerDevPixel() / 60.0; 1.351 + } 1.352 + 1.353 + if (changedPos) { 1.354 + if (changedSize && !aMoveOnly) { 1.355 + widget->ResizeClient(newBounds.x * invScale, 1.356 + newBounds.y * invScale, 1.357 + newBounds.width * invScale, 1.358 + newBounds.height * invScale, 1.359 + aInvalidateChangedSize); 1.360 + } else { 1.361 + widget->MoveClient(newBounds.x * invScale, 1.362 + newBounds.y * invScale); 1.363 + } 1.364 + } else { 1.365 + if (changedSize && !aMoveOnly) { 1.366 + widget->ResizeClient(newBounds.width * invScale, 1.367 + newBounds.height * invScale, 1.368 + aInvalidateChangedSize); 1.369 + } // else do nothing! 1.370 + } 1.371 + 1.372 + if (!curVisibility && newVisibility) { 1.373 + widget->Show(true); 1.374 + } 1.375 +} 1.376 + 1.377 +void nsView::SetDimensions(const nsRect& aRect, bool aPaint, bool aResizeWidget) 1.378 +{ 1.379 + nsRect dims = aRect; 1.380 + dims.MoveBy(mPosX, mPosY); 1.381 + 1.382 + // Don't use nsRect's operator== here, since it returns true when 1.383 + // both rects are empty even if they have different widths and we 1.384 + // have cases where that sort of thing matters to us. 1.385 + if (mDimBounds.TopLeft() == dims.TopLeft() && 1.386 + mDimBounds.Size() == dims.Size()) { 1.387 + return; 1.388 + } 1.389 + 1.390 + mDimBounds = dims; 1.391 + 1.392 + if (aResizeWidget) { 1.393 + ResetWidgetBounds(false, false); 1.394 + } 1.395 +} 1.396 + 1.397 +void nsView::NotifyEffectiveVisibilityChanged(bool aEffectivelyVisible) 1.398 +{ 1.399 + if (!aEffectivelyVisible) 1.400 + { 1.401 + DropMouseGrabbing(); 1.402 + } 1.403 + 1.404 + SetForcedRepaint(true); 1.405 + 1.406 + if (nullptr != mWindow) 1.407 + { 1.408 + ResetWidgetBounds(false, false); 1.409 + } 1.410 + 1.411 + for (nsView* child = mFirstChild; child; child = child->mNextSibling) { 1.412 + if (child->mVis == nsViewVisibility_kHide) { 1.413 + // It was effectively hidden and still is 1.414 + continue; 1.415 + } 1.416 + // Our child is visible if we are 1.417 + child->NotifyEffectiveVisibilityChanged(aEffectivelyVisible); 1.418 + } 1.419 +} 1.420 + 1.421 +void nsView::SetVisibility(nsViewVisibility aVisibility) 1.422 +{ 1.423 + mVis = aVisibility; 1.424 + NotifyEffectiveVisibilityChanged(IsEffectivelyVisible()); 1.425 +} 1.426 + 1.427 +void nsView::SetFloating(bool aFloatingView) 1.428 +{ 1.429 + if (aFloatingView) 1.430 + mVFlags |= NS_VIEW_FLAG_FLOATING; 1.431 + else 1.432 + mVFlags &= ~NS_VIEW_FLAG_FLOATING; 1.433 +} 1.434 + 1.435 +void nsView::InvalidateHierarchy(nsViewManager *aViewManagerParent) 1.436 +{ 1.437 + if (mViewManager->GetRootView() == this) 1.438 + mViewManager->InvalidateHierarchy(); 1.439 + 1.440 + for (nsView *child = mFirstChild; child; child = child->GetNextSibling()) 1.441 + child->InvalidateHierarchy(aViewManagerParent); 1.442 +} 1.443 + 1.444 +void nsView::InsertChild(nsView *aChild, nsView *aSibling) 1.445 +{ 1.446 + NS_PRECONDITION(nullptr != aChild, "null ptr"); 1.447 + 1.448 + if (nullptr != aChild) 1.449 + { 1.450 + if (nullptr != aSibling) 1.451 + { 1.452 +#ifdef DEBUG 1.453 + NS_ASSERTION(aSibling->GetParent() == this, "tried to insert view with invalid sibling"); 1.454 +#endif 1.455 + //insert after sibling 1.456 + aChild->SetNextSibling(aSibling->GetNextSibling()); 1.457 + aSibling->SetNextSibling(aChild); 1.458 + } 1.459 + else 1.460 + { 1.461 + aChild->SetNextSibling(mFirstChild); 1.462 + mFirstChild = aChild; 1.463 + } 1.464 + aChild->SetParent(this); 1.465 + 1.466 + // If we just inserted a root view, then update the RootViewManager 1.467 + // on all view managers in the new subtree. 1.468 + 1.469 + nsViewManager *vm = aChild->GetViewManager(); 1.470 + if (vm->GetRootView() == aChild) 1.471 + { 1.472 + aChild->InvalidateHierarchy(nullptr); // don't care about releasing grabs 1.473 + } 1.474 + } 1.475 +} 1.476 + 1.477 +void nsView::RemoveChild(nsView *child) 1.478 +{ 1.479 + NS_PRECONDITION(nullptr != child, "null ptr"); 1.480 + 1.481 + if (nullptr != child) 1.482 + { 1.483 + nsView* prevKid = nullptr; 1.484 + nsView* kid = mFirstChild; 1.485 + DebugOnly<bool> found = false; 1.486 + while (nullptr != kid) { 1.487 + if (kid == child) { 1.488 + if (nullptr != prevKid) { 1.489 + prevKid->SetNextSibling(kid->GetNextSibling()); 1.490 + } else { 1.491 + mFirstChild = kid->GetNextSibling(); 1.492 + } 1.493 + child->SetParent(nullptr); 1.494 + found = true; 1.495 + break; 1.496 + } 1.497 + prevKid = kid; 1.498 + kid = kid->GetNextSibling(); 1.499 + } 1.500 + NS_ASSERTION(found, "tried to remove non child"); 1.501 + 1.502 + // If we just removed a root view, then update the RootViewManager 1.503 + // on all view managers in the removed subtree. 1.504 + 1.505 + nsViewManager *vm = child->GetViewManager(); 1.506 + if (vm->GetRootView() == child) 1.507 + { 1.508 + child->InvalidateHierarchy(GetViewManager()); 1.509 + } 1.510 + } 1.511 +} 1.512 + 1.513 +// Native widgets ultimately just can't deal with the awesome power of 1.514 +// CSS2 z-index. However, we set the z-index on the widget anyway 1.515 +// because in many simple common cases the widgets do end up in the 1.516 +// right order. We set each widget's z-index to the z-index of the 1.517 +// nearest ancestor that has non-auto z-index. 1.518 +static void UpdateNativeWidgetZIndexes(nsView* aView, int32_t aZIndex) 1.519 +{ 1.520 + if (aView->HasWidget()) { 1.521 + nsIWidget* widget = aView->GetWidget(); 1.522 + if (widget->GetZIndex() != aZIndex) { 1.523 + widget->SetZIndex(aZIndex); 1.524 + } 1.525 + } else { 1.526 + for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) { 1.527 + if (v->GetZIndexIsAuto()) { 1.528 + UpdateNativeWidgetZIndexes(v, aZIndex); 1.529 + } 1.530 + } 1.531 + } 1.532 +} 1.533 + 1.534 +static int32_t FindNonAutoZIndex(nsView* aView) 1.535 +{ 1.536 + while (aView) { 1.537 + if (!aView->GetZIndexIsAuto()) { 1.538 + return aView->GetZIndex(); 1.539 + } 1.540 + aView = aView->GetParent(); 1.541 + } 1.542 + return 0; 1.543 +} 1.544 + 1.545 +struct DefaultWidgetInitData : public nsWidgetInitData { 1.546 + DefaultWidgetInitData() : nsWidgetInitData() 1.547 + { 1.548 + mWindowType = eWindowType_child; 1.549 + clipChildren = true; 1.550 + clipSiblings = true; 1.551 + } 1.552 +}; 1.553 + 1.554 +nsresult nsView::CreateWidget(nsWidgetInitData *aWidgetInitData, 1.555 + bool aEnableDragDrop, 1.556 + bool aResetVisibility) 1.557 +{ 1.558 + AssertNoWindow(); 1.559 + NS_ABORT_IF_FALSE(!aWidgetInitData || 1.560 + aWidgetInitData->mWindowType != eWindowType_popup, 1.561 + "Use CreateWidgetForPopup"); 1.562 + 1.563 + DefaultWidgetInitData defaultInitData; 1.564 + bool initDataPassedIn = !!aWidgetInitData; 1.565 + aWidgetInitData = aWidgetInitData ? aWidgetInitData : &defaultInitData; 1.566 + defaultInitData.mListenForResizes = 1.567 + (!initDataPassedIn && GetParent() && 1.568 + GetParent()->GetViewManager() != mViewManager); 1.569 + 1.570 + nsIntRect trect = CalcWidgetBounds(aWidgetInitData->mWindowType); 1.571 + 1.572 + nsRefPtr<nsDeviceContext> dx = mViewManager->GetDeviceContext(); 1.573 + 1.574 + nsIWidget* parentWidget = 1.575 + GetParent() ? GetParent()->GetNearestWidget(nullptr) : nullptr; 1.576 + if (!parentWidget) { 1.577 + NS_ERROR("nsView::CreateWidget without suitable parent widget??"); 1.578 + return NS_ERROR_FAILURE; 1.579 + } 1.580 + 1.581 + // XXX: using aForceUseIWidgetParent=true to preserve previous 1.582 + // semantics. It's not clear that it's actually needed. 1.583 + mWindow = parentWidget->CreateChild(trect, dx, aWidgetInitData, 1.584 + true).take(); 1.585 + if (!mWindow) { 1.586 + return NS_ERROR_FAILURE; 1.587 + } 1.588 + 1.589 + InitializeWindow(aEnableDragDrop, aResetVisibility); 1.590 + 1.591 + return NS_OK; 1.592 +} 1.593 + 1.594 +nsresult nsView::CreateWidgetForParent(nsIWidget* aParentWidget, 1.595 + nsWidgetInitData *aWidgetInitData, 1.596 + bool aEnableDragDrop, 1.597 + bool aResetVisibility) 1.598 +{ 1.599 + AssertNoWindow(); 1.600 + NS_ABORT_IF_FALSE(!aWidgetInitData || 1.601 + aWidgetInitData->mWindowType != eWindowType_popup, 1.602 + "Use CreateWidgetForPopup"); 1.603 + NS_ABORT_IF_FALSE(aParentWidget, "Parent widget required"); 1.604 + 1.605 + DefaultWidgetInitData defaultInitData; 1.606 + aWidgetInitData = aWidgetInitData ? aWidgetInitData : &defaultInitData; 1.607 + 1.608 + nsIntRect trect = CalcWidgetBounds(aWidgetInitData->mWindowType); 1.609 + 1.610 + nsRefPtr<nsDeviceContext> dx = mViewManager->GetDeviceContext(); 1.611 + 1.612 + mWindow = 1.613 + aParentWidget->CreateChild(trect, dx, aWidgetInitData).take(); 1.614 + if (!mWindow) { 1.615 + return NS_ERROR_FAILURE; 1.616 + } 1.617 + 1.618 + InitializeWindow(aEnableDragDrop, aResetVisibility); 1.619 + 1.620 + return NS_OK; 1.621 +} 1.622 + 1.623 +nsresult nsView::CreateWidgetForPopup(nsWidgetInitData *aWidgetInitData, 1.624 + nsIWidget* aParentWidget, 1.625 + bool aEnableDragDrop, 1.626 + bool aResetVisibility) 1.627 +{ 1.628 + AssertNoWindow(); 1.629 + NS_ABORT_IF_FALSE(aWidgetInitData, "Widget init data required"); 1.630 + NS_ABORT_IF_FALSE(aWidgetInitData->mWindowType == eWindowType_popup, 1.631 + "Use one of the other CreateWidget methods"); 1.632 + 1.633 + nsIntRect trect = CalcWidgetBounds(aWidgetInitData->mWindowType); 1.634 + 1.635 + nsRefPtr<nsDeviceContext> dx = mViewManager->GetDeviceContext(); 1.636 + 1.637 + // XXX/cjones: having these two separate creation cases seems ... um 1.638 + // ... unnecessary, but it's the way the old code did it. Please 1.639 + // unify them by first finding a suitable parent nsIWidget, then 1.640 + // getting rid of aForceUseIWidgetParent. 1.641 + if (aParentWidget) { 1.642 + // XXX: using aForceUseIWidgetParent=true to preserve previous 1.643 + // semantics. It's not clear that it's actually needed. 1.644 + mWindow = aParentWidget->CreateChild(trect, dx, aWidgetInitData, 1.645 + true).take(); 1.646 + } 1.647 + else { 1.648 + nsIWidget* nearestParent = GetParent() ? GetParent()->GetNearestWidget(nullptr) 1.649 + : nullptr; 1.650 + if (!nearestParent) { 1.651 + // Without a parent, we can't make a popup. This can happen 1.652 + // when printing 1.653 + return NS_ERROR_FAILURE; 1.654 + } 1.655 + 1.656 + mWindow = 1.657 + nearestParent->CreateChild(trect, dx, aWidgetInitData).take(); 1.658 + } 1.659 + if (!mWindow) { 1.660 + return NS_ERROR_FAILURE; 1.661 + } 1.662 + 1.663 + InitializeWindow(aEnableDragDrop, aResetVisibility); 1.664 + 1.665 + return NS_OK; 1.666 +} 1.667 + 1.668 +void 1.669 +nsView::InitializeWindow(bool aEnableDragDrop, bool aResetVisibility) 1.670 +{ 1.671 + NS_ABORT_IF_FALSE(mWindow, "Must have a window to initialize"); 1.672 + 1.673 + mWindow->SetWidgetListener(this); 1.674 + 1.675 + if (aEnableDragDrop) { 1.676 + mWindow->EnableDragDrop(true); 1.677 + } 1.678 + 1.679 + // propagate the z-index to the widget. 1.680 + UpdateNativeWidgetZIndexes(this, FindNonAutoZIndex(this)); 1.681 + 1.682 + //make sure visibility state is accurate 1.683 + 1.684 + if (aResetVisibility) { 1.685 + SetVisibility(GetVisibility()); 1.686 + } 1.687 +} 1.688 + 1.689 +// Attach to a top level widget and start receiving mirrored events. 1.690 +nsresult nsView::AttachToTopLevelWidget(nsIWidget* aWidget) 1.691 +{ 1.692 + NS_PRECONDITION(nullptr != aWidget, "null widget ptr"); 1.693 + /// XXXjimm This is a temporary workaround to an issue w/document 1.694 + // viewer (bug 513162). 1.695 + nsIWidgetListener* listener = aWidget->GetAttachedWidgetListener(); 1.696 + if (listener) { 1.697 + nsView *oldView = listener->GetView(); 1.698 + if (oldView) { 1.699 + oldView->DetachFromTopLevelWidget(); 1.700 + } 1.701 + } 1.702 + 1.703 + nsRefPtr<nsDeviceContext> dx = mViewManager->GetDeviceContext(); 1.704 + 1.705 + // Note, the previous device context will be released. Detaching 1.706 + // will not restore the old one. 1.707 + nsresult rv = aWidget->AttachViewToTopLevel(!nsIWidget::UsePuppetWidgets(), dx); 1.708 + if (NS_FAILED(rv)) 1.709 + return rv; 1.710 + 1.711 + mWindow = aWidget; 1.712 + NS_ADDREF(mWindow); 1.713 + 1.714 + mWindow->SetAttachedWidgetListener(this); 1.715 + mWindow->EnableDragDrop(true); 1.716 + mWidgetIsTopLevel = true; 1.717 + 1.718 + // Refresh the view bounds 1.719 + CalcWidgetBounds(mWindow->WindowType()); 1.720 + 1.721 + return NS_OK; 1.722 +} 1.723 + 1.724 +// Detach this view from an attached widget. 1.725 +nsresult nsView::DetachFromTopLevelWidget() 1.726 +{ 1.727 + NS_PRECONDITION(mWidgetIsTopLevel, "Not attached currently!"); 1.728 + NS_PRECONDITION(mWindow, "null mWindow for DetachFromTopLevelWidget!"); 1.729 + 1.730 + mWindow->SetAttachedWidgetListener(nullptr); 1.731 + NS_RELEASE(mWindow); 1.732 + 1.733 + mWidgetIsTopLevel = false; 1.734 + 1.735 + return NS_OK; 1.736 +} 1.737 + 1.738 +void nsView::SetZIndex(bool aAuto, int32_t aZIndex) 1.739 +{ 1.740 + bool oldIsAuto = GetZIndexIsAuto(); 1.741 + mVFlags = (mVFlags & ~NS_VIEW_FLAG_AUTO_ZINDEX) | (aAuto ? NS_VIEW_FLAG_AUTO_ZINDEX : 0); 1.742 + mZIndex = aZIndex; 1.743 + 1.744 + if (HasWidget() || !oldIsAuto || !aAuto) { 1.745 + UpdateNativeWidgetZIndexes(this, FindNonAutoZIndex(this)); 1.746 + } 1.747 +} 1.748 + 1.749 +void nsView::AssertNoWindow() 1.750 +{ 1.751 + // XXX: it would be nice to make this a strong assert 1.752 + if (MOZ_UNLIKELY(mWindow)) { 1.753 + NS_ERROR("We already have a window for this view? BAD"); 1.754 + mWindow->SetWidgetListener(nullptr); 1.755 + mWindow->Destroy(); 1.756 + NS_RELEASE(mWindow); 1.757 + } 1.758 +} 1.759 + 1.760 +// 1.761 +// internal window creation functions 1.762 +// 1.763 +void nsView::AttachWidgetEventHandler(nsIWidget* aWidget) 1.764 +{ 1.765 +#ifdef DEBUG 1.766 + NS_ASSERTION(!aWidget->GetWidgetListener(), "Already have a widget listener"); 1.767 +#endif 1.768 + 1.769 + aWidget->SetWidgetListener(this); 1.770 +} 1.771 + 1.772 +void nsView::DetachWidgetEventHandler(nsIWidget* aWidget) 1.773 +{ 1.774 + NS_ASSERTION(!aWidget->GetWidgetListener() || 1.775 + aWidget->GetWidgetListener()->GetView() == this, "Wrong view"); 1.776 + aWidget->SetWidgetListener(nullptr); 1.777 +} 1.778 + 1.779 +#ifdef DEBUG 1.780 +void nsView::List(FILE* out, int32_t aIndent) const 1.781 +{ 1.782 + int32_t i; 1.783 + for (i = aIndent; --i >= 0; ) fputs(" ", out); 1.784 + fprintf(out, "%p ", (void*)this); 1.785 + if (nullptr != mWindow) { 1.786 + nscoord p2a = mViewManager->AppUnitsPerDevPixel(); 1.787 + nsIntRect rect; 1.788 + mWindow->GetClientBounds(rect); 1.789 + nsRect windowBounds = rect.ToAppUnits(p2a); 1.790 + mWindow->GetBounds(rect); 1.791 + nsRect nonclientBounds = rect.ToAppUnits(p2a); 1.792 + nsrefcnt widgetRefCnt = mWindow->AddRef() - 1; 1.793 + mWindow->Release(); 1.794 + int32_t Z = mWindow->GetZIndex(); 1.795 + fprintf(out, "(widget=%p[%" PRIuPTR "] z=%d pos={%d,%d,%d,%d}) ", 1.796 + (void*)mWindow, widgetRefCnt, Z, 1.797 + nonclientBounds.x, nonclientBounds.y, 1.798 + windowBounds.width, windowBounds.height); 1.799 + } 1.800 + nsRect brect = GetBounds(); 1.801 + fprintf(out, "{%d,%d,%d,%d}", 1.802 + brect.x, brect.y, brect.width, brect.height); 1.803 + fprintf(out, " z=%d vis=%d frame=%p <\n", 1.804 + mZIndex, mVis, static_cast<void*>(mFrame)); 1.805 + for (nsView* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { 1.806 + NS_ASSERTION(kid->GetParent() == this, "incorrect parent"); 1.807 + kid->List(out, aIndent + 1); 1.808 + } 1.809 + for (i = aIndent; --i >= 0; ) fputs(" ", out); 1.810 + fputs(">\n", out); 1.811 +} 1.812 +#endif // DEBUG 1.813 + 1.814 +nsPoint nsView::GetOffsetTo(const nsView* aOther) const 1.815 +{ 1.816 + return GetOffsetTo(aOther, GetViewManager()->AppUnitsPerDevPixel()); 1.817 +} 1.818 + 1.819 +nsPoint nsView::GetOffsetTo(const nsView* aOther, const int32_t aAPD) const 1.820 +{ 1.821 + NS_ABORT_IF_FALSE(GetParent() || !aOther || aOther->GetParent() || 1.822 + this == aOther, "caller of (outer) GetOffsetTo must not " 1.823 + "pass unrelated views"); 1.824 + // We accumulate the final result in offset 1.825 + nsPoint offset(0, 0); 1.826 + // The offset currently accumulated at the current APD 1.827 + nsPoint docOffset(0, 0); 1.828 + const nsView* v = this; 1.829 + nsViewManager* currVM = v->GetViewManager(); 1.830 + int32_t currAPD = currVM->AppUnitsPerDevPixel(); 1.831 + const nsView* root = nullptr; 1.832 + for ( ; v != aOther && v; root = v, v = v->GetParent()) { 1.833 + nsViewManager* newVM = v->GetViewManager(); 1.834 + if (newVM != currVM) { 1.835 + int32_t newAPD = newVM->AppUnitsPerDevPixel(); 1.836 + if (newAPD != currAPD) { 1.837 + offset += docOffset.ConvertAppUnits(currAPD, aAPD); 1.838 + docOffset.x = docOffset.y = 0; 1.839 + currAPD = newAPD; 1.840 + } 1.841 + currVM = newVM; 1.842 + } 1.843 + docOffset += v->GetPosition(); 1.844 + } 1.845 + offset += docOffset.ConvertAppUnits(currAPD, aAPD); 1.846 + 1.847 + if (v != aOther) { 1.848 + // Looks like aOther wasn't an ancestor of |this|. So now we have 1.849 + // the root-VM-relative position of |this| in |offset|. Get the 1.850 + // root-VM-relative position of aOther and subtract it. 1.851 + nsPoint negOffset = aOther->GetOffsetTo(root, aAPD); 1.852 + offset -= negOffset; 1.853 + } 1.854 + 1.855 + return offset; 1.856 +} 1.857 + 1.858 +nsPoint nsView::GetOffsetToWidget(nsIWidget* aWidget) const 1.859 +{ 1.860 + nsPoint pt; 1.861 + // Get the view for widget 1.862 + nsView* widgetView = GetViewFor(aWidget); 1.863 + if (!widgetView) { 1.864 + return pt; 1.865 + } 1.866 + 1.867 + // Get the offset to the widget view in the widget view's APD 1.868 + // We get the offset in the widget view's APD first and then convert to our 1.869 + // APD afterwards so that we can include the widget view's ViewToWidgetOffset 1.870 + // in the sum in its native APD, and then convert the whole thing to our APD 1.871 + // so that we don't have to convert the APD of the relatively small 1.872 + // ViewToWidgetOffset by itself with a potentially large relative rounding 1.873 + // error. 1.874 + pt = -widgetView->GetOffsetTo(this); 1.875 + // Add in the offset to the widget. 1.876 + pt += widgetView->ViewToWidgetOffset(); 1.877 + 1.878 + // Convert to our appunits. 1.879 + int32_t widgetAPD = widgetView->GetViewManager()->AppUnitsPerDevPixel(); 1.880 + int32_t ourAPD = GetViewManager()->AppUnitsPerDevPixel(); 1.881 + pt = pt.ConvertAppUnits(widgetAPD, ourAPD); 1.882 + return pt; 1.883 +} 1.884 + 1.885 +nsIWidget* nsView::GetNearestWidget(nsPoint* aOffset) const 1.886 +{ 1.887 + return GetNearestWidget(aOffset, GetViewManager()->AppUnitsPerDevPixel()); 1.888 +} 1.889 + 1.890 +nsIWidget* nsView::GetNearestWidget(nsPoint* aOffset, const int32_t aAPD) const 1.891 +{ 1.892 + // aOffset is based on the view's position, which ignores any chrome on 1.893 + // attached parent widgets. 1.894 + 1.895 + // We accumulate the final result in pt 1.896 + nsPoint pt(0, 0); 1.897 + // The offset currently accumulated at the current APD 1.898 + nsPoint docPt(0,0); 1.899 + const nsView* v = this; 1.900 + nsViewManager* currVM = v->GetViewManager(); 1.901 + int32_t currAPD = currVM->AppUnitsPerDevPixel(); 1.902 + for ( ; v && !v->HasWidget(); v = v->GetParent()) { 1.903 + nsViewManager* newVM = v->GetViewManager(); 1.904 + if (newVM != currVM) { 1.905 + int32_t newAPD = newVM->AppUnitsPerDevPixel(); 1.906 + if (newAPD != currAPD) { 1.907 + pt += docPt.ConvertAppUnits(currAPD, aAPD); 1.908 + docPt.x = docPt.y = 0; 1.909 + currAPD = newAPD; 1.910 + } 1.911 + currVM = newVM; 1.912 + } 1.913 + docPt += v->GetPosition(); 1.914 + } 1.915 + if (!v) { 1.916 + if (aOffset) { 1.917 + pt += docPt.ConvertAppUnits(currAPD, aAPD); 1.918 + *aOffset = pt; 1.919 + } 1.920 + return nullptr; 1.921 + } 1.922 + 1.923 + // pt is now the offset from v's origin to this view's origin. 1.924 + // We add the ViewToWidgetOffset to get the offset to the widget. 1.925 + if (aOffset) { 1.926 + docPt += v->ViewToWidgetOffset(); 1.927 + pt += docPt.ConvertAppUnits(currAPD, aAPD); 1.928 + *aOffset = pt; 1.929 + } 1.930 + return v->GetWidget(); 1.931 +} 1.932 + 1.933 +bool nsView::IsRoot() const 1.934 +{ 1.935 + NS_ASSERTION(mViewManager != nullptr," View manager is null in nsView::IsRoot()"); 1.936 + return mViewManager->GetRootView() == this; 1.937 +} 1.938 + 1.939 +nsRect 1.940 +nsView::GetBoundsInParentUnits() const 1.941 +{ 1.942 + nsView* parent = GetParent(); 1.943 + nsViewManager* VM = GetViewManager(); 1.944 + if (this != VM->GetRootView() || !parent) { 1.945 + return mDimBounds; 1.946 + } 1.947 + int32_t ourAPD = VM->AppUnitsPerDevPixel(); 1.948 + int32_t parentAPD = parent->GetViewManager()->AppUnitsPerDevPixel(); 1.949 + return mDimBounds.ConvertAppUnitsRoundOut(ourAPD, parentAPD); 1.950 +} 1.951 + 1.952 +nsPoint 1.953 +nsView::ConvertFromParentCoords(nsPoint aPt) const 1.954 +{ 1.955 + const nsView* parent = GetParent(); 1.956 + if (parent) { 1.957 + aPt = aPt.ConvertAppUnits(parent->GetViewManager()->AppUnitsPerDevPixel(), 1.958 + GetViewManager()->AppUnitsPerDevPixel()); 1.959 + } 1.960 + aPt -= GetPosition(); 1.961 + return aPt; 1.962 +} 1.963 + 1.964 +static bool 1.965 +IsPopupWidget(nsIWidget* aWidget) 1.966 +{ 1.967 + return (aWidget->WindowType() == eWindowType_popup); 1.968 +} 1.969 + 1.970 +nsIPresShell* 1.971 +nsView::GetPresShell() 1.972 +{ 1.973 + return GetViewManager()->GetPresShell(); 1.974 +} 1.975 + 1.976 +bool 1.977 +nsView::WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y) 1.978 +{ 1.979 + nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); 1.980 + if (pm && IsPopupWidget(aWidget)) { 1.981 + pm->PopupMoved(mFrame, nsIntPoint(x, y)); 1.982 + return true; 1.983 + } 1.984 + 1.985 + return false; 1.986 +} 1.987 + 1.988 +bool 1.989 +nsView::WindowResized(nsIWidget* aWidget, int32_t aWidth, int32_t aHeight) 1.990 +{ 1.991 + // The root view may not be set if this is the resize associated with 1.992 + // window creation 1.993 + SetForcedRepaint(true); 1.994 + if (this == mViewManager->GetRootView()) { 1.995 + nsRefPtr<nsDeviceContext> devContext = mViewManager->GetDeviceContext(); 1.996 + // ensure DPI is up-to-date, in case of window being opened and sized 1.997 + // on a non-default-dpi display (bug 829963) 1.998 + devContext->CheckDPIChange(); 1.999 + int32_t p2a = devContext->AppUnitsPerDevPixel(); 1.1000 + mViewManager->SetWindowDimensions(NSIntPixelsToAppUnits(aWidth, p2a), 1.1001 + NSIntPixelsToAppUnits(aHeight, p2a)); 1.1002 + 1.1003 + nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); 1.1004 + if (pm) { 1.1005 + nsIPresShell* presShell = mViewManager->GetPresShell(); 1.1006 + if (presShell && presShell->GetDocument()) { 1.1007 + pm->AdjustPopupsOnWindowChange(presShell); 1.1008 + } 1.1009 + } 1.1010 + 1.1011 + return true; 1.1012 + } 1.1013 + else if (IsPopupWidget(aWidget)) { 1.1014 + nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); 1.1015 + if (pm) { 1.1016 + pm->PopupResized(mFrame, nsIntSize(aWidth, aHeight)); 1.1017 + return true; 1.1018 + } 1.1019 + } 1.1020 + 1.1021 + return false; 1.1022 +} 1.1023 + 1.1024 +bool 1.1025 +nsView::RequestWindowClose(nsIWidget* aWidget) 1.1026 +{ 1.1027 + if (mFrame && IsPopupWidget(aWidget) && 1.1028 + mFrame->GetType() == nsGkAtoms::menuPopupFrame) { 1.1029 + nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); 1.1030 + if (pm) { 1.1031 + pm->HidePopup(mFrame->GetContent(), false, true, false, false); 1.1032 + return true; 1.1033 + } 1.1034 + } 1.1035 + 1.1036 + return false; 1.1037 +} 1.1038 + 1.1039 +void 1.1040 +nsView::WillPaintWindow(nsIWidget* aWidget) 1.1041 +{ 1.1042 + nsRefPtr<nsViewManager> vm = mViewManager; 1.1043 + vm->WillPaintWindow(aWidget); 1.1044 +} 1.1045 + 1.1046 +bool 1.1047 +nsView::PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion) 1.1048 +{ 1.1049 + NS_ASSERTION(this == nsView::GetViewFor(aWidget), "wrong view for widget?"); 1.1050 + 1.1051 + nsRefPtr<nsViewManager> vm = mViewManager; 1.1052 + bool result = vm->PaintWindow(aWidget, aRegion); 1.1053 + return result; 1.1054 +} 1.1055 + 1.1056 +void 1.1057 +nsView::DidPaintWindow() 1.1058 +{ 1.1059 + nsRefPtr<nsViewManager> vm = mViewManager; 1.1060 + vm->DidPaintWindow(); 1.1061 +} 1.1062 + 1.1063 +void 1.1064 +nsView::DidCompositeWindow() 1.1065 +{ 1.1066 + nsIPresShell* presShell = mViewManager->GetPresShell(); 1.1067 + if (presShell) { 1.1068 + nsAutoScriptBlocker scriptBlocker; 1.1069 + presShell->GetPresContext()->GetDisplayRootPresContext()->GetRootPresContext()->NotifyDidPaintForSubtree(nsIPresShell::PAINT_COMPOSITE); 1.1070 + } 1.1071 +} 1.1072 + 1.1073 +void 1.1074 +nsView::RequestRepaint() 1.1075 +{ 1.1076 + nsIPresShell* presShell = mViewManager->GetPresShell(); 1.1077 + if (presShell) { 1.1078 + presShell->ScheduleViewManagerFlush(); 1.1079 + } 1.1080 +} 1.1081 + 1.1082 +nsEventStatus 1.1083 +nsView::HandleEvent(WidgetGUIEvent* aEvent, 1.1084 + bool aUseAttachedEvents) 1.1085 +{ 1.1086 + NS_PRECONDITION(nullptr != aEvent->widget, "null widget ptr"); 1.1087 + 1.1088 + nsEventStatus result = nsEventStatus_eIgnore; 1.1089 + nsView* view; 1.1090 + if (aUseAttachedEvents) { 1.1091 + nsIWidgetListener* listener = aEvent->widget->GetAttachedWidgetListener(); 1.1092 + view = listener ? listener->GetView() : nullptr; 1.1093 + } 1.1094 + else { 1.1095 + view = GetViewFor(aEvent->widget); 1.1096 + } 1.1097 + 1.1098 + if (view) { 1.1099 + nsRefPtr<nsViewManager> vm = view->GetViewManager(); 1.1100 + vm->DispatchEvent(aEvent, view, &result); 1.1101 + } 1.1102 + 1.1103 + return result; 1.1104 +}