/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
We assume that a widget is z-ordered on top of its parent.
We do NOT assume anything about the relative z-ordering of sibling widgets. Even though we ask for a specific z-order, we don't assume that widget z-ordering actually works.
*/
nsViewManager::~nsViewManager() { if (mRootView) { // Destroy any remaining views
mRootView->Destroy();
mRootView = nullptr;
}
mRootViewManager = nullptr;
MOZ_RELEASE_ASSERT(!mPresShell, "Releasing nsViewManager without having called Destroy on " "the PresShell!");
}
// We don't hold a reference to the presentation context because it // holds a reference to us.
nsresult nsViewManager::Init(nsDeviceContext* aContext) {
MOZ_ASSERT(nullptr != aContext, "null ptr");
if (nullptr == aContext) { return NS_ERROR_NULL_POINTER;
} if (nullptr != mContext) { return NS_ERROR_ALREADY_INITIALIZED;
}
mContext = aContext;
// Do NOT destroy the current root view. It's the caller's responsibility // to destroy it
mRootView = aView;
if (mRootView) {
nsView* parent = mRootView->GetParent(); if (parent) { // Calling InsertChild on |parent| will InvalidateHierarchy() on us, so // no need to set mRootViewManager ourselves here.
parent->InsertChild(mRootView, nullptr);
} else {
InvalidateHierarchy();
}
} // Else don't touch mRootViewManager
}
void nsViewManager::DoSetWindowDimensions(nscoord aWidth, nscoord aHeight) {
nsRect oldDim = mRootView->GetDimensions();
nsRect newDim(0, 0, aWidth, aHeight); // We care about resizes even when one dimension is already zero. if (oldDim.IsEqualEdges(newDim)) { return;
} // Don't resize the widget. It is already being set elsewhere.
mRootView->SetDimensions(newDim, true, false); if (RefPtr<PresShell> presShell = mPresShell) {
presShell->ResizeReflow(aWidth, aHeight);
}
}
bool nsViewManager::ShouldDelayResize() const {
MOZ_ASSERT(mRootView); if (!mRootView->IsEffectivelyVisible() || !mPresShell ||
!mPresShell->IsVisible()) { returntrue;
} if (nsRefreshDriver* rd = mPresShell->GetRefreshDriver()) { if (rd->IsResizeSuppressed()) { returntrue;
}
} returnfalse;
}
void nsViewManager::SetWindowDimensions(nscoord aWidth, nscoord aHeight, bool aDelayResize) { if (mRootView) { if (!ShouldDelayResize() && !aDelayResize) { if (mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
mDelayedResize != nsSize(aWidth, aHeight)) { // We have a delayed resize; that now obsolete size may already have // been flushed to the PresContext so we need to update the PresContext // with the new size because if the new size is exactly the same as the // root view's current size then DoSetWindowDimensions will not // request a resize reflow (which would correct it). See bug 617076.
mDelayedResize = nsSize(aWidth, aHeight);
FlushDelayedResize();
}
mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE);
DoSetWindowDimensions(aWidth, aHeight);
} else {
mDelayedResize.SizeTo(aWidth, aHeight); if (mPresShell) {
mPresShell->SetNeedStyleFlush();
mPresShell->SetNeedLayoutFlush();
}
}
}
}
// Convert aIn from being relative to and in appunits of aFromView, to being // relative to and in appunits of aToView. static nsRect ConvertRectBetweenViews(const nsRect& aIn, nsView* aFromView,
nsView* aToView) {
nsRect out = aIn;
out.MoveBy(aFromView->GetOffsetTo(aToView));
out = out.ScaleToOtherAppUnitsRoundOut(
aFromView->GetViewManager()->AppUnitsPerDevPixel(),
aToView->GetViewManager()->AppUnitsPerDevPixel()); return out;
}
// Any popup view is a display root. if (displayRoot->GetFrame() &&
displayRoot->GetFrame()->IsMenuPopupFrame()) { return displayRoot;
}
displayRoot = displayParent;
}
}
/** aRegion is given in device coordinates!! aContext may be null, in which case layers should be used for rendering.
*/ void nsViewManager::Refresh(nsView* aView, const LayoutDeviceIntRegion& aRegion) {
NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
if (mPresShell && mPresShell->IsNeverPainting()) { return;
}
if (aRegion.IsEmpty()) { return;
}
nsIWidget* widget = aView->GetWidget(); if (!widget) { return;
}
NS_ASSERTION(!IsPainting(), "recursive painting not permitted"); if (IsPainting()) {
RootViewManager()->mRecursiveRefreshPending = true; return;
}
void nsViewManager::ProcessPendingUpdatesPaint(nsIWidget* aWidget) { if (aWidget->NeedsPaint()) { // If an ancestor widget was hidden and then shown, we could // have a delayed resize to handle. for (RefPtr<nsViewManager> vm = this; vm;
vm = vm->mRootView->GetParent()
? vm->mRootView->GetParent()->GetViewManager()
: nullptr) { if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
vm->mRootView->IsEffectivelyVisible() && vm->mPresShell &&
vm->mPresShell->IsVisible()) {
vm->FlushDelayedResize();
}
}
nsView* view = nsView::GetViewFor(aWidget);
if (!view) {
NS_ERROR("FlushDelayedResize destroyed the nsView?"); return;
}
#ifdef MOZ_DUMP_PAINTING if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf_stderr("---- PAINT END ----\n");
} #endif
}
}
FlushDirtyRegionToWidget(nsView::GetViewFor(aWidget));
}
void nsViewManager::FlushDirtyRegionToWidget(nsView* aView) {
NS_ASSERTION(aView->GetViewManager() == this, "FlushDirtyRegionToWidget called on view we don't own");
/** * @param aDamagedRegion this region, relative to aWidgetView, is invalidated in * every widget child of aWidgetView, plus aWidgetView's own widget
*/ void nsViewManager::InvalidateWidgetArea(nsView* aWidgetView, const nsRegion& aDamagedRegion) {
NS_ASSERTION(aWidgetView->GetViewManager() == this, "InvalidateWidgetArea called on view we don't own");
nsIWidget* widget = aWidgetView->GetWidget();
// If the widget is hidden, it don't cover nothing if (widget && !widget->IsVisible()) { return;
}
if (!widget) { // The root view or a scrolling view might not have a widget // (for example, during printing). We get here when we scroll // during printing to show selected options in a listbox, for example. return;
}
if (!aDamagedRegion.IsEmpty()) { for (auto iter = aDamagedRegion.RectIter(); !iter.Done(); iter.Next()) {
LayoutDeviceIntRect bounds = ViewToWidget(aWidgetView, iter.Get());
widget->Invalidate(bounds);
}
}
}
void nsViewManager::InvalidateView(nsView* aView) { // If painting is suppressed in the presshell or an ancestor drop all // invalidates, it will invalidate everything when it unsuppresses. if (ShouldIgnoreInvalidation(this)) { return;
}
NS_ASSERTION(aView->GetViewManager() == this, "InvalidateView called on view we don't own");
if (aView->GetBounds().IsEmpty()) { return;
}
GetDisplayRootFor(aView)->SetIsDirty(true);
}
void nsViewManager::InvalidateViews(nsView* aView) { // Invalidate this view.
InvalidateView(aView);
// Invalidate all children as well.
nsView* childView = aView->GetFirstChild(); while (nullptr != childView) {
childView->GetViewManager()->InvalidateViews(childView);
childView = childView->GetNextSibling();
}
}
void nsViewManager::WillPaintWindow(nsIWidget* aWidget) { if (aWidget) {
nsView* view = nsView::GetViewFor(aWidget);
WindowRenderer* renderer = aWidget->GetWindowRenderer(); if (view &&
(view->ForcedRepaint() || !renderer->NeedsWidgetInvalidation())) {
ProcessPendingUpdates(); // Re-get the view pointer here since the ProcessPendingUpdates might have // destroyed it during CallWillPaintOnObservers.
view = nsView::GetViewFor(aWidget); if (view) {
view->SetForcedRepaint(false);
}
}
}
}
NS_ASSERTION(
IsPaintingAllowed(), "shouldn't be receiving paint events while painting is disallowed!");
// Get the view pointer here since NS_WILL_PAINT might have // destroyed it during CallWillPaintOnObservers (bug 378273).
nsView* view = nsView::GetViewFor(aWidget); if (view && !aRegion.IsEmpty()) {
Refresh(view, aRegion);
}
WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); if ((mouseEvent && // Ignore mouse events that we synthesize.
mouseEvent->mReason == WidgetMouseEvent::eReal && // Ignore mouse exit and enter (we'll get moves if the user // is really moving the mouse) since we get them when we // create and destroy widgets.
mouseEvent->mMessage != eMouseExitFromWidget &&
mouseEvent->mMessage != eMouseEnterIntoWidget) ||
aEvent->HasKeyEventMessage() || aEvent->HasIMEEventMessage()) {
gLastUserEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
}
// Find the view whose coordinates system we're in.
nsView* view = aView; bool dispatchUsingCoordinates = aEvent->IsUsingCoordinates(); if (dispatchUsingCoordinates) { // Will dispatch using coordinates. Pretty bogus but it's consistent // with what presshell does.
view = GetDisplayRootFor(view);
}
// If the view has no frame, look for a view that does.
nsIFrame* frame = view->GetFrame(); if (!frame && (dispatchUsingCoordinates || aEvent->HasKeyEventMessage() ||
aEvent->IsIMERelatedEvent())) { while (view && !view->GetFrame()) {
view = view->GetParent();
}
if (view) {
frame = view->GetFrame();
}
}
if (nullptr != frame) { // Hold a refcount to the presshell. The continued existence of the // presshell will delay deletion of this view hierarchy should the event // want to cause its destruction in, say, some JavaScript event handler. if (RefPtr<PresShell> presShell = view->GetViewManager()->GetPresShell()) {
presShell->HandleEvent(frame, aEvent, false, aStatus); return;
}
}
if ((nullptr != aParent) && (nullptr != aChild)) { // if aAfter is set, we will insert the child after 'prev' (i.e. after 'kid' // in document order, otherwise after 'kid' (i.e. before 'kid' in document // order).
if (nullptr == aSibling) { if (aAfter) { // insert at end of document order, i.e., before first view // this is the common case, by far
aParent->InsertChild(aChild, nullptr);
} else { // insert at beginning of document order, i.e., after last view
nsView* kid = aParent->GetFirstChild();
nsView* prev = nullptr; while (kid) {
prev = kid;
kid = kid->GetNextSibling();
} // prev is last view or null if there are no children
aParent->InsertChild(aChild, prev);
}
} else {
nsView* kid = aParent->GetFirstChild();
nsView* prev = nullptr; while (kid && aSibling != kid) { // get the next sibling view
prev = kid;
kid = kid->GetNextSibling();
}
NS_ASSERTION(kid != nullptr, "couldn't find sibling in child list"); if (aAfter) { // insert after 'kid' in document order, i.e. before in view order
aParent->InsertChild(aChild, prev);
} else { // insert before 'kid' in document order, i.e. after in view order
aParent->InsertChild(aChild, kid);
}
}
}
}
void nsViewManager::RemoveChild(nsView* aChild) {
NS_ASSERTION(aChild, "aChild must not be null");
nsView* parent = aChild->GetParent();
if (nullptr != parent) {
NS_ASSERTION(
aChild->GetViewManager() == this || parent->GetViewManager() == this, "wrong view manager");
parent->RemoveChild(aChild);
}
}
nsRect oldDimensions = aView->GetDimensions(); if (!oldDimensions.IsEqualEdges(aRect)) {
aView->SetDimensions(aRect, true);
}
// Note that if layout resizes the view and the view has a custom clip // region set, then we expect layout to update the clip region too. Thus // in the case where mClipRect has been optimized away to just be a null // pointer, and this resize is implicitly changing the clip rect, it's OK // because layout will change it back again if necessary.
}
if (aVisible != aView->GetVisibility()) {
aView->SetVisibility(aVisible);
}
}
bool nsViewManager::IsViewInserted(nsView* aView) { if (mRootView == aView) { returntrue;
} if (aView->GetParent() == nullptr) { returnfalse;
}
nsView* view = aView->GetParent()->GetFirstChild(); while (view != nullptr) { if (view == aView) { returntrue;
}
view = view->GetNextSibling();
} returnfalse;
}
nsViewManager* nsViewManager::IncrementDisableRefreshCount() { if (!IsRootVM()) { return RootViewManager()->IncrementDisableRefreshCount();
}
++mRefreshDisableCount;
returnthis;
}
void nsViewManager::DecrementDisableRefreshCount() {
NS_ASSERTION(IsRootVM(), "Should only be called on root");
--mRefreshDisableCount;
NS_ASSERTION(mRefreshDisableCount >= 0, "Invalid refresh disable count!");
}
nsIWidget* nsViewManager::GetRootWidget() const { if (!mRootView) { return nullptr;
} if (mRootView->HasWidget()) { return mRootView->GetWidget();
} if (mRootView->GetParent()) { return mRootView->GetParent()->GetViewManager()->GetRootWidget();
} return nullptr;
}
// Flush things like reflows by calling WillPaint on observer presShells. if (mPresShell) {
mPresShell->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush();
void nsViewManager::InvalidateHierarchy() { if (mRootView) {
mRootViewManager = nullptr;
nsView* parent = mRootView->GetParent(); if (parent) {
mRootViewManager = parent->GetViewManager()->RootViewManager();
NS_ASSERTION(mRootViewManager != this, "Root view had a parent, but it has the same view manager");
} // else, we are implicitly our own root view manager.
}
}
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.