Esempio n. 1
0
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;
}
Esempio n. 2
0
nsresult
nsResizerFrame::HandleEvent(nsPresContext* aPresContext,
                            WidgetGUIEvent* aEvent,
                            nsEventStatus* aEventStatus)
{
  NS_ENSURE_ARG_POINTER(aEventStatus);
  if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
    return NS_OK;
  }

  nsWeakFrame weakFrame(this);
  bool doDefault = true;

  switch (aEvent->mMessage) {
    case eTouchStart:
    case eMouseDown: {
      if (aEvent->mClass == eTouchEventClass ||
          (aEvent->mClass == eMouseEventClass &&
           aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton)) {
        nsCOMPtr<nsIBaseWindow> window;
        nsIPresShell* presShell = aPresContext->GetPresShell();
        nsIContent* contentToResize =
          GetContentToResize(presShell, getter_AddRefs(window));
        if (contentToResize) {
          nsIFrame* frameToResize = contentToResize->GetPrimaryFrame();
          if (!frameToResize)
            break;

          // cache the content rectangle for the frame to resize
          // GetScreenRectInAppUnits returns the border box rectangle, so
          // adjust to get the desired content rectangle.
          nsRect rect = frameToResize->GetScreenRectInAppUnits();
          switch (frameToResize->StylePosition()->mBoxSizing) {
            case StyleBoxSizing::Content:
              rect.Deflate(frameToResize->GetUsedPadding());
              MOZ_FALLTHROUGH;
            case StyleBoxSizing::Padding:
              rect.Deflate(frameToResize->GetUsedBorder());
              MOZ_FALLTHROUGH;
            case StyleBoxSizing::Border:
              // nothing
              break;
          }

          mMouseDownRect =
            LayoutDeviceIntRect::FromAppUnitsToNearest(rect, aPresContext->AppUnitsPerDevPixel());
          doDefault = false;
        }
        else {
          // If there is no window, then resizing isn't allowed.
          if (!window)
            break;

          doDefault = false;

          // ask the widget implementation to begin a resize drag if it can
          Direction direction = GetDirection();
          nsresult rv = aEvent->mWidget->BeginResizeDrag(aEvent,
                        direction.mHorizontal, direction.mVertical);
          // for native drags, don't set the fields below
          if (rv != NS_ERROR_NOT_IMPLEMENTED)
             break;
             
          // if there's no native resize support, we need to do window
          // resizing ourselves
          window->GetPositionAndSize(&mMouseDownRect.x, &mMouseDownRect.y,
                                     &mMouseDownRect.width, &mMouseDownRect.height);
        }

        // remember current mouse coordinates
        LayoutDeviceIntPoint refPoint;
        if (!GetEventPoint(aEvent, refPoint))
          return NS_OK;
        mMouseDownPoint = refPoint + aEvent->mWidget->WidgetToScreenOffset();

        // we're tracking
        mTrackingMouseMove = true;

        nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED);
      }
    }
    break;

  case eTouchEnd:
  case eMouseUp: {
    if (aEvent->mClass == eTouchEventClass ||
        (aEvent->mClass == eMouseEventClass &&
         aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton)) {
      // we're done tracking.
      mTrackingMouseMove = false;

      nsIPresShell::SetCapturingContent(nullptr, 0);

      doDefault = false;
    }
  }
  break;

  case eTouchMove:
  case eMouseMove: {
    if (mTrackingMouseMove)
    {
      nsCOMPtr<nsIBaseWindow> window;
      nsIPresShell* presShell = aPresContext->GetPresShell();
      nsCOMPtr<nsIContent> contentToResize =
        GetContentToResize(presShell, getter_AddRefs(window));

      // check if the returned content really is a menupopup
      nsMenuPopupFrame* menuPopupFrame = nullptr;
      if (contentToResize) {
        menuPopupFrame = do_QueryFrame(contentToResize->GetPrimaryFrame());
      }

      // both MouseMove and direction are negative when pointing to the
      // top and left, and positive when pointing to the bottom and right

      // retrieve the offset of the mousemove event relative to the mousedown.
      // The difference is how much the resize needs to be
      LayoutDeviceIntPoint refPoint;
      if (!GetEventPoint(aEvent, refPoint))
        return NS_OK;
      LayoutDeviceIntPoint screenPoint =
        refPoint + aEvent->mWidget->WidgetToScreenOffset();
      LayoutDeviceIntPoint mouseMove(screenPoint - mMouseDownPoint);

      // Determine which direction to resize by checking the dir attribute.
      // For windows and menus, ensure that it can be resized in that direction.
      Direction direction = GetDirection();
      if (window || menuPopupFrame) {
        if (menuPopupFrame) {
          menuPopupFrame->CanAdjustEdges(
            (direction.mHorizontal == -1) ? NS_SIDE_LEFT : NS_SIDE_RIGHT,
            (direction.mVertical == -1) ? NS_SIDE_TOP : NS_SIDE_BOTTOM, mouseMove);
        }
      }
      else if (!contentToResize) {
        break; // don't do anything if there's nothing to resize
      }

      LayoutDeviceIntRect rect = mMouseDownRect;

      // Check if there are any size constraints on this window.
      widget::SizeConstraints sizeConstraints;
      if (window) {
        nsCOMPtr<nsIWidget> widget;
        window->GetMainWidget(getter_AddRefs(widget));
        sizeConstraints = widget->GetSizeConstraints();
      }

      AdjustDimensions(&rect.x, &rect.width, sizeConstraints.mMinSize.width,
                       sizeConstraints.mMaxSize.width, mouseMove.x, direction.mHorizontal);
      AdjustDimensions(&rect.y, &rect.height, sizeConstraints.mMinSize.height,
                       sizeConstraints.mMaxSize.height, mouseMove.y, direction.mVertical);

      // Don't allow resizing a window or a popup past the edge of the screen,
      // so adjust the rectangle to fit within the available screen area.
      if (window) {
        nsCOMPtr<nsIScreen> screen;
        nsCOMPtr<nsIScreenManager> sm(do_GetService("@mozilla.org/gfx/screenmanager;1"));
        if (sm) {
          nsIntRect frameRect = GetScreenRect();
          // ScreenForRect requires display pixels, so scale from device pix
          double scale;
          window->GetUnscaledDevicePixelsPerCSSPixel(&scale);
          sm->ScreenForRect(NSToIntRound(frameRect.x / scale),
                            NSToIntRound(frameRect.y / scale), 1, 1,
                            getter_AddRefs(screen));
          if (screen) {
            LayoutDeviceIntRect screenRect;
            screen->GetRect(&screenRect.x, &screenRect.y,
                            &screenRect.width, &screenRect.height);
            rect.IntersectRect(rect, screenRect);
          }
        }
      }
      else if (menuPopupFrame) {
        nsRect frameRect = menuPopupFrame->GetScreenRectInAppUnits();
        nsIFrame* rootFrame = aPresContext->PresShell()->FrameManager()->GetRootFrame();
        nsRect rootScreenRect = rootFrame->GetScreenRectInAppUnits();

        nsPopupLevel popupLevel = menuPopupFrame->PopupLevel();
        int32_t appPerDev = aPresContext->AppUnitsPerDevPixel();
        LayoutDeviceIntRect screenRect = menuPopupFrame->GetConstraintRect
          (LayoutDeviceIntRect::FromAppUnitsToNearest(frameRect, appPerDev),
           // round using ...ToInside as it's better to be a pixel too small
           // than be too large. If the popup is too large it could get flipped
           // to the opposite side of the anchor point while resizing.
           LayoutDeviceIntRect::FromAppUnitsToInside(rootScreenRect, appPerDev),
           popupLevel);
        rect.IntersectRect(rect, screenRect);
      }

      if (contentToResize) {
        // convert the rectangle into css pixels. When changing the size in a
        // direction, don't allow the new size to be less that the resizer's
        // size. This ensures that content isn't resized too small as to make
        // the resizer invisible.
        nsRect appUnitsRect = ToAppUnits(rect.ToUnknownRect(), aPresContext->AppUnitsPerDevPixel());
        if (appUnitsRect.width < mRect.width && mouseMove.x)
          appUnitsRect.width = mRect.width;
        if (appUnitsRect.height < mRect.height && mouseMove.y)
          appUnitsRect.height = mRect.height;
        nsIntRect cssRect = appUnitsRect.ToInsidePixels(nsPresContext::AppUnitsPerCSSPixel());

        LayoutDeviceIntRect oldRect;
        nsWeakFrame weakFrame(menuPopupFrame);
        if (menuPopupFrame) {
          nsCOMPtr<nsIWidget> widget = menuPopupFrame->GetWidget();
          if (widget)
            widget->GetScreenBounds(oldRect);

          // convert the new rectangle into outer window coordinates
          LayoutDeviceIntPoint clientOffset = widget->GetClientOffset();
          rect.x -= clientOffset.x;
          rect.y -= clientOffset.y;
        }

        SizeInfo sizeInfo, originalSizeInfo;
        sizeInfo.width.AppendInt(cssRect.width);
        sizeInfo.height.AppendInt(cssRect.height);
        ResizeContent(contentToResize, direction, sizeInfo, &originalSizeInfo);
        MaybePersistOriginalSize(contentToResize, originalSizeInfo);

        // Move the popup to the new location unless it is anchored, since
        // the position shouldn't change. nsMenuPopupFrame::SetPopupPosition
        // will instead ensure that the popup's position is anchored at the
        // right place.
        if (weakFrame.IsAlive() &&
            (oldRect.x != rect.x || oldRect.y != rect.y) &&
            (!menuPopupFrame->IsAnchored() ||
             menuPopupFrame->PopupLevel() != ePopupLevelParent)) {

          CSSPoint cssPos = rect.TopLeft() / aPresContext->CSSToDevPixelScale();
          menuPopupFrame->MoveTo(RoundedToInt(cssPos), true);
        }
      }
      else {
        window->SetPositionAndSize(rect.x, rect.y, rect.width, rect.height, true); // do the repaint.
      }

      doDefault = false;
    }
  }
  break;

  case eMouseClick: {
    WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
    if (mouseEvent->IsLeftClickEvent()) {
      MouseClicked(mouseEvent);
    }
    break;
  }
  case eMouseDoubleClick:
    if (aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) {
      nsCOMPtr<nsIBaseWindow> window;
      nsIPresShell* presShell = aPresContext->GetPresShell();
      nsIContent* contentToResize =
        GetContentToResize(presShell, getter_AddRefs(window));
      if (contentToResize) {
        nsMenuPopupFrame* menuPopupFrame = do_QueryFrame(contentToResize->GetPrimaryFrame());
        if (menuPopupFrame)
          break; // Don't restore original sizing for menupopup frames until
                 // we handle screen constraints here. (Bug 357725)

        RestoreOriginalSize(contentToResize);
      }
    }
    break;

  default:
    break;
  }

  if (!doDefault)
    *aEventStatus = nsEventStatus_eConsumeNoDefault;

  if (doDefault && weakFrame.IsAlive())
    return nsTitleBarFrame::HandleEvent(aPresContext, aEvent, aEventStatus);

  return NS_OK;
}
Esempio n. 3
0
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);
  }
}
Esempio n. 4
0
/**
 * @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 0
  nsRect dbgBounds = aDamagedRegion.GetBounds();
  printf("InvalidateWidgetArea view:%X (%d) widget:%X region: %d, %d, %d, %d\n",
    aWidgetView, aWidgetView->IsAttachedToTopLevel(),
    widget, dbgBounds.x, dbgBounds.y, dbgBounds.width, dbgBounds.height);
#endif

  // 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;
  }

  // Update all child widgets with the damage. In the process,
  // accumulate the union of all the child widget areas, or at least
  // some subset of that.
  nsRegion children;
  if (widget->GetTransparencyMode() != eTransparencyTransparent) {
    for (nsIWidget* childWidget = widget->GetFirstChild();
         childWidget;
         childWidget = childWidget->GetNextSibling()) {
      nsView* view = nsView::GetViewFor(childWidget);
      NS_ASSERTION(view != aWidgetView, "will recur infinitely");
      nsWindowType type = childWidget->WindowType();
      if (view && childWidget->IsVisible() && type != eWindowType_popup) {
        NS_ASSERTION(childWidget->IsPlugin(),
                     "Only plugin or popup widgets can be children!");

        // We do not need to invalidate in plugin widgets, but we should
        // exclude them from the invalidation region IF we're not on
        // Mac. On Mac we need to draw under plugin widgets, because
        // plugin widgets are basically invisible
#ifndef XP_MACOSX
        // GetBounds should compensate for chrome on a toplevel widget
        LayoutDeviceIntRect bounds;
        childWidget->GetBounds(bounds);

        nsTArray<LayoutDeviceIntRect> clipRects;
        childWidget->GetWindowClipRegion(&clipRects);
        for (uint32_t i = 0; i < clipRects.Length(); ++i) {
          nsRect rr = LayoutDeviceIntRect::ToAppUnits(
            clipRects[i] + bounds.TopLeft(), AppUnitsPerDevPixel());
          children.Or(children, rr - aWidgetView->ViewToWidgetOffset());
          children.SimplifyInward(20);
        }
#endif
      }
    }
  }

  nsRegion leftOver;
  leftOver.Sub(aDamagedRegion, children);

  if (!leftOver.IsEmpty()) {
    for (auto iter = leftOver.RectIter(); !iter.Done(); iter.Next()) {
      LayoutDeviceIntRect bounds = ViewToWidget(aWidgetView, iter.Get());
      widget->Invalidate(bounds);
    }
  }
}
nsresult
nsTitleBarFrame::HandleEvent(nsPresContext* aPresContext,
                             WidgetGUIEvent* aEvent,
                             nsEventStatus* aEventStatus)
{
    NS_ENSURE_ARG_POINTER(aEventStatus);
    if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
        return NS_OK;
    }

    bool doDefault = true;

    switch (aEvent->mMessage) {

    case eMouseDown: {
        if (aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) {
            // titlebar has no effect in non-chrome shells
            nsCOMPtr<nsIDocShellTreeItem> dsti = aPresContext->GetDocShell();
            if (dsti) {
                if (dsti->ItemType() == nsIDocShellTreeItem::typeChrome) {
                    // we're tracking.
                    mTrackingMouseMove = true;

                    // start capture.
                    nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED);

                    // remember current mouse coordinates.
                    mLastPoint = aEvent->mRefPoint;
                }
            }

            *aEventStatus = nsEventStatus_eConsumeNoDefault;
            doDefault = false;
        }
    }
    break;


    case eMouseUp: {
        if (mTrackingMouseMove &&
                aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) {
            // we're done tracking.
            mTrackingMouseMove = false;

            // end capture
            nsIPresShell::SetCapturingContent(nullptr, 0);

            *aEventStatus = nsEventStatus_eConsumeNoDefault;
            doDefault = false;
        }
    }
    break;

    case eMouseMove: {
        if(mTrackingMouseMove)
        {
            LayoutDeviceIntPoint nsMoveBy = aEvent->mRefPoint - mLastPoint;

            nsIFrame* parent = GetParent();
            while (parent) {
                nsMenuPopupFrame* popupFrame = do_QueryFrame(parent);
                if (popupFrame)
                    break;
                parent = parent->GetParent();
            }

            // if the titlebar is in a popup, move the popup frame, otherwise
            // move the widget associated with the window
            if (parent) {
                nsMenuPopupFrame* menuPopupFrame = static_cast<nsMenuPopupFrame*>(parent);
                nsCOMPtr<nsIWidget> widget = menuPopupFrame->GetWidget();
                LayoutDeviceIntRect bounds = widget->GetScreenBounds();

                CSSPoint cssPos = (bounds.TopLeft() + nsMoveBy)
                                  / aPresContext->CSSToDevPixelScale();
                menuPopupFrame->MoveTo(RoundedToInt(cssPos), false);
            }
            else {
                nsIPresShell* presShell = aPresContext->PresShell();
                nsPIDOMWindowOuter *window = presShell->GetDocument()->GetWindow();
                if (window) {
                    window->MoveBy(nsMoveBy.x, nsMoveBy.y);
                }
            }

            *aEventStatus = nsEventStatus_eConsumeNoDefault;

            doDefault = false;
        }
    }
    break;

    case eMouseClick: {
        WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
        if (mouseEvent->IsLeftClickEvent()) {
            MouseClicked(mouseEvent);
        }
        break;
    }

    default:
        break;
    }

    if ( doDefault )
        return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
    else
        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 = 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);
  }
}