void PuppetWidget::Resize(double aWidth, double aHeight, bool aRepaint) { LayoutDeviceIntRect oldBounds = mBounds; mBounds.SizeTo(LayoutDeviceIntSize(NSToIntRound(aWidth), NSToIntRound(aHeight))); if (mChild) { mChild->Resize(aWidth, aHeight, aRepaint); return; } // XXX: roc says that |aRepaint| dictates whether or not to // invalidate the expanded area if (oldBounds.Size() < mBounds.Size() && aRepaint) { LayoutDeviceIntRegion dirty(mBounds); dirty.Sub(dirty, oldBounds); InvalidateRegion(this, dirty); } // call WindowResized() on both the current listener, and possibly // also the previous one if we're in a state where we're drawing that one // because the current one is paint suppressed if (!oldBounds.IsEqualEdges(mBounds) && mAttachedWidgetListener) { if (GetCurrentWidgetListener() && GetCurrentWidgetListener() != mAttachedWidgetListener) { GetCurrentWidgetListener()->WindowResized(this, mBounds.width, mBounds.height); } mAttachedWidgetListener->WindowResized(this, mBounds.width, mBounds.height); } }
void CompositorD3D9::EnsureSize() { LayoutDeviceIntRect rect; mWidget->GetClientBounds(rect); mSize = rect.Size(); }
nsresult PuppetWidget::ConfigureChildren(const nsTArray<Configuration>& aConfigurations) { for (uint32_t i = 0; i < aConfigurations.Length(); ++i) { const Configuration& configuration = aConfigurations[i]; PuppetWidget* w = static_cast<PuppetWidget*>(configuration.mChild.get()); NS_ASSERTION(w->GetParent() == this, "Configured widget is not a child"); w->SetWindowClipRegion(configuration.mClipRegion, true); LayoutDeviceIntRect bounds = w->GetBounds(); if (bounds.Size() != configuration.mBounds.Size()) { w->Resize(configuration.mBounds.x, configuration.mBounds.y, configuration.mBounds.width, configuration.mBounds.height, true); } else if (bounds.TopLeft() != configuration.mBounds.TopLeft()) { w->Move(configuration.mBounds.x, configuration.mBounds.y); } w->SetWindowClipRegion(configuration.mClipRegion, false); } return NS_OK; }
void nsView::DoResetWidgetBounds(bool aMoveOnly, bool aInvalidateChangedSize) { // The geometry of a root view's widget is controlled externally, // NOT by sizing or positioning the view if (mViewManager->GetRootView() == this) { return; } NS_PRECONDITION(mWindow, "Why was this called??"); // Hold this ref to make sure it stays alive. nsCOMPtr<nsIWidget> widget = mWindow; // Stash a copy of these and use them so we can handle this being deleted (say // from sync painting/flushing from Show/Move/Resize on the widget). LayoutDeviceIntRect newBounds; RefPtr<nsDeviceContext> dx = mViewManager->GetDeviceContext(); nsWindowType type = widget->WindowType(); LayoutDeviceIntRect curBounds; widget->GetClientBounds(curBounds); bool invisiblePopup = type == eWindowType_popup && ((curBounds.IsEmpty() && mDimBounds.IsEmpty()) || mVis == nsViewVisibility_kHide); if (invisiblePopup) { // We're going to hit the early exit below, avoid calling CalcWidgetBounds. } else { newBounds = LayoutDeviceIntRect::FromUnknownRect(CalcWidgetBounds(type)); } bool curVisibility = widget->IsVisible(); bool newVisibility = IsEffectivelyVisible(); if (curVisibility && !newVisibility) { widget->Show(false); } if (invisiblePopup) { // Don't manipulate empty or hidden popup widgets. For example there's no // point moving hidden comboboxes around, or doing X server roundtrips // to compute their true screen position. This could mean that WidgetToScreen // operations on these widgets don't return up-to-date values, but popup // positions aren't reliable anyway because of correction to be on or off-screen. return; } bool changedPos = curBounds.TopLeft() != newBounds.TopLeft(); bool changedSize = curBounds.Size() != newBounds.Size(); // Child views are never attached to top level widgets, this is safe. // Coordinates are converted to display pixels for window Move/Resize APIs, // because of the potential for device-pixel coordinate spaces for mixed // hidpi/lodpi screens to overlap each other and result in bad placement // (bug 814434). double invScale; // Bug 861270: for correct widget manipulation at arbitrary scale factors, // prefer to base scaling on widget->GetDefaultScale(). But only do this if // it matches the view manager's device context scale after allowing for the // quantization to app units, because of OS X multiscreen issues (where the // only two scales are 1.0 or 2.0, and so the quantization doesn't actually // cause problems anyhow). // In the case of a mismatch, fall back to scaling based on the dev context's // AppUnitsPerDevPixelAtUnitFullZoom value. On platforms where the device-pixel // scale is uniform across all displays (currently all except OS X), we'll // always use the precise value from mWindow->GetDefaultScale here. CSSToLayoutDeviceScale scale = widget->GetDefaultScale(); if (NSToIntRound(60.0 / scale.scale) == dx->AppUnitsPerDevPixelAtUnitFullZoom()) { invScale = 1.0 / scale.scale; } else { invScale = dx->AppUnitsPerDevPixelAtUnitFullZoom() / 60.0; } if (changedPos) { if (changedSize && !aMoveOnly) { widget->ResizeClient(newBounds.x * invScale, newBounds.y * invScale, newBounds.width * invScale, newBounds.height * invScale, aInvalidateChangedSize); } else { widget->MoveClient(newBounds.x * invScale, newBounds.y * invScale); } } else { if (changedSize && !aMoveOnly) { widget->ResizeClient(newBounds.width * invScale, newBounds.height * invScale, aInvalidateChangedSize); } // else do nothing! } if (!curVisibility && newVisibility) { widget->Show(true); } }
LayoutDeviceIntRect nsView::CalcWidgetBounds(nsWindowType aType) { int32_t p2a = mViewManager->AppUnitsPerDevPixel(); nsRect viewBounds(mDimBounds); nsView* parent = GetParent(); nsIWidget* parentWidget = nullptr; if (parent) { nsPoint offset; parentWidget = parent->GetNearestWidget(&offset, p2a); // make viewBounds be relative to the parent widget, in appunits viewBounds += offset; if (parentWidget && aType == eWindowType_popup && IsEffectivelyVisible()) { // put offset into screen coordinates. (based on client area origin) LayoutDeviceIntPoint screenPoint = parentWidget->WidgetToScreenOffset(); viewBounds += nsPoint(NSIntPixelsToAppUnits(screenPoint.x, p2a), NSIntPixelsToAppUnits(screenPoint.y, p2a)); } } // Compute widget bounds in device pixels LayoutDeviceIntRect newBounds = LayoutDeviceIntRect::FromUnknownRect(viewBounds.ToNearestPixels(p2a)); #if defined(XP_MACOSX) || (MOZ_WIDGET_GTK == 3) // cocoa and GTK round widget coordinates to the nearest global "display // pixel" integer value. So we avoid fractional display pixel values by // rounding to the nearest value that won't yield a fractional display pixel. nsIWidget* widget = parentWidget ? parentWidget : mWindow.get(); uint32_t round; if (aType == eWindowType_popup && widget && ((round = widget->RoundsWidgetCoordinatesTo()) > 1)) { LayoutDeviceIntSize pixelRoundedSize = newBounds.Size(); // round the top left and bottom right to the nearest round pixel newBounds.x = NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.x, p2a) / round) * round; newBounds.y = NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.y, p2a) / round) * round; newBounds.width = NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.XMost(), p2a) / round) * round - newBounds.x; newBounds.height = NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.YMost(), p2a) / round) * round - newBounds.y; // but if that makes the widget larger then our frame may not paint the // extra pixels, so reduce the size to the nearest round value if (newBounds.width > pixelRoundedSize.width) { newBounds.width -= round; } if (newBounds.height > pixelRoundedSize.height) { newBounds.height -= round; } } #endif // Compute where the top-left of our widget ended up relative to the parent // widget, in appunits. nsPoint roundedOffset(NSIntPixelsToAppUnits(newBounds.x, p2a), NSIntPixelsToAppUnits(newBounds.y, p2a)); // mViewToWidgetOffset is added to coordinates relative to the view origin // to get coordinates relative to the widget. // The view origin, relative to the parent widget, is at // (mPosX,mPosY) - mDimBounds.TopLeft() + viewBounds.TopLeft(). // Our widget, relative to the parent widget, is roundedOffset. mViewToWidgetOffset = nsPoint(mPosX, mPosY) - mDimBounds.TopLeft() + viewBounds.TopLeft() - roundedOffset; return newBounds; }
void nsView::DoResetWidgetBounds(bool aMoveOnly, bool aInvalidateChangedSize) { // The geometry of a root view's widget is controlled externally, // NOT by sizing or positioning the view if (mViewManager->GetRootView() == this) { return; } NS_PRECONDITION(mWindow, "Why was this called??"); // Hold this ref to make sure it stays alive. nsCOMPtr<nsIWidget> widget = mWindow; // Stash a copy of these and use them so we can handle this being deleted (say // from sync painting/flushing from Show/Move/Resize on the widget). LayoutDeviceIntRect newBounds; RefPtr<nsDeviceContext> dx = mViewManager->GetDeviceContext(); nsWindowType type = widget->WindowType(); LayoutDeviceIntRect curBounds; widget->GetClientBounds(curBounds); bool invisiblePopup = type == eWindowType_popup && ((curBounds.IsEmpty() && mDimBounds.IsEmpty()) || mVis == nsViewVisibility_kHide); if (invisiblePopup) { // We're going to hit the early exit below, avoid calling CalcWidgetBounds. } else { newBounds = CalcWidgetBounds(type); } bool curVisibility = widget->IsVisible(); bool newVisibility = IsEffectivelyVisible(); if (curVisibility && !newVisibility) { widget->Show(false); } if (invisiblePopup) { // Don't manipulate empty or hidden popup widgets. For example there's no // point moving hidden comboboxes around, or doing X server roundtrips // to compute their true screen position. This could mean that WidgetToScreen // operations on these widgets don't return up-to-date values, but popup // positions aren't reliable anyway because of correction to be on or off-screen. return; } bool changedPos = curBounds.TopLeft() != newBounds.TopLeft(); bool changedSize = curBounds.Size() != newBounds.Size(); // Child views are never attached to top level widgets, this is safe. // Coordinates are converted to desktop pixels for window Move/Resize APIs, // because of the potential for device-pixel coordinate spaces for mixed // hidpi/lodpi screens to overlap each other and result in bad placement // (bug 814434). DesktopToLayoutDeviceScale scale = widget->GetDesktopToDeviceScale(); #ifdef XP_MACOSX // On OS X, this can be called before Cocoa has updated the backing scale // factor of our widget, in which case |scale| is wrong here. To work // around this, we check the device context and override |scale| if it // doesn't match. (This happens when a popup window that has previously // been created and hidden is being moved between hi- and lo-dpi screens, // but is not currently visible; Cocoa doesn't notify it of the scale // factor change until it gets shown on the new screen, which is too late // for us because we'll have already done the computations involving scale // here to move/size it.) // It might be better to avoid this by keeping calculations such as // CalcWidgetBounds entirely in appUnits, rather than using device pixels, // but that seems like a more extensive and potentially risky change. int32_t appPerDev = dx->AppUnitsPerDevPixelAtUnitFullZoom(); if (NSToIntRound(60.0 / scale.scale) != appPerDev) { scale = DesktopToLayoutDeviceScale(60.0 / appPerDev); } #endif DesktopRect deskRect = newBounds / scale; if (changedPos) { if (changedSize && !aMoveOnly) { widget->ResizeClient(deskRect.x, deskRect.y, deskRect.width, deskRect.height, aInvalidateChangedSize); } else { widget->MoveClient(deskRect.x, deskRect.y); } } else { if (changedSize && !aMoveOnly) { widget->ResizeClient(deskRect.width, deskRect.height, aInvalidateChangedSize); } // else do nothing! } if (!curVisibility && newVisibility) { widget->Show(true); } }