Пример #1
0
bool
ContentCacheInParent::GetTextRect(uint32_t aOffset,
                                  LayoutDeviceIntRect& aTextRect) const
{
  MOZ_LOG(sContentCacheLog, LogLevel::Info,
    ("ContentCacheInParent: 0x%p GetTextRect(aOffset=%u), "
     "mTextRectArray={ mStart=%u, mRects.Length()=%u }, "
     "mSelection={ mAnchor=%u, mFocus=%u }",
     this, aOffset, mTextRectArray.mStart, mTextRectArray.mRects.Length(),
     mSelection.mAnchor, mSelection.mFocus));

  if (!aOffset) {
    NS_WARN_IF(mFirstCharRect.IsEmpty());
    aTextRect = mFirstCharRect;
    return !aTextRect.IsEmpty();
  }
  if (aOffset == mSelection.mAnchor) {
    NS_WARN_IF(mSelection.mAnchorCharRect.IsEmpty());
    aTextRect = mSelection.mAnchorCharRect;
    return !aTextRect.IsEmpty();
  }
  if (aOffset == mSelection.mFocus) {
    NS_WARN_IF(mSelection.mFocusCharRect.IsEmpty());
    aTextRect = mSelection.mFocusCharRect;
    return !aTextRect.IsEmpty();
  }

  if (!mTextRectArray.InRange(aOffset)) {
    aTextRect.SetEmpty();
    return false;
  }
  aTextRect = mTextRectArray.GetRect(aOffset);
  return true;
}
Пример #2
0
already_AddRefed<gfx::DrawTarget>
CompositorWidgetProxy::CreateBackBufferDrawTarget(gfx::DrawTarget* aScreenTarget,
                                                  const LayoutDeviceIntRect& aRect,
                                                  const LayoutDeviceIntRect& aClearRect)
{
  MOZ_ASSERT(aScreenTarget);
  gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8;
  gfx::IntSize size = aRect.ToUnknownRect().Size();
  gfx::IntSize clientSize(GetClientSize().ToUnknownSize());

  RefPtr<gfx::DrawTarget> target;
  // Re-use back buffer if possible
  if (mLastBackBuffer &&
      mLastBackBuffer->GetBackendType() == aScreenTarget->GetBackendType() &&
      mLastBackBuffer->GetFormat() == format &&
      size <= mLastBackBuffer->GetSize() &&
      mLastBackBuffer->GetSize() <= clientSize) {
    target = mLastBackBuffer;
    target->SetTransform(gfx::Matrix());
    if (!aClearRect.IsEmpty()) {
      gfx::IntRect clearRect = aClearRect.ToUnknownRect() - aRect.ToUnknownRect().TopLeft();
      target->ClearRect(gfx::Rect(clearRect.x, clearRect.y, clearRect.width, clearRect.height));
    }
  } else {
    target = aScreenTarget->CreateSimilarDrawTarget(size, format);
    mLastBackBuffer = target;
  }
  return target.forget();
}
Пример #3
0
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);
  }
}
Пример #4
0
static void CalculatePluginClip(const LayoutDeviceIntRect& aBounds,
                                const nsTArray<LayoutDeviceIntRect>& aPluginClipRects,
                                const LayoutDeviceIntPoint& aContentOffset,
                                const LayoutDeviceIntRegion& aParentLayerVisibleRegion,
                                nsTArray<LayoutDeviceIntRect>& aResult,
                                LayoutDeviceIntRect& aVisibleBounds,
                                bool& aPluginIsVisible)
{
  aPluginIsVisible = true;
  LayoutDeviceIntRegion contentVisibleRegion;
  // aPluginClipRects (plugin widget origin) - contains *visible* rects
  for (uint32_t idx = 0; idx < aPluginClipRects.Length(); idx++) {
    LayoutDeviceIntRect rect = aPluginClipRects[idx];
    // shift to content origin
    rect.MoveBy(aBounds.x, aBounds.y);
    // accumulate visible rects
    contentVisibleRegion.OrWith(rect);
  }
  // apply layers clip (window origin)
  LayoutDeviceIntRegion region = aParentLayerVisibleRegion;
  region.MoveBy(-aContentOffset.x, -aContentOffset.y);
  contentVisibleRegion.AndWith(region);
  if (contentVisibleRegion.IsEmpty()) {
    aPluginIsVisible = false;
    return;
  }
  // shift to plugin widget origin
  contentVisibleRegion.MoveBy(-aBounds.x, -aBounds.y);
  LayoutDeviceIntRegion::RectIterator iter(contentVisibleRegion);
  for (const LayoutDeviceIntRect* rgnRect = iter.Next(); rgnRect; rgnRect = iter.Next()) {
    aResult.AppendElement(*rgnRect);
    aVisibleBounds.UnionRect(aVisibleBounds, *rgnRect);
  }
}
Пример #5
0
void
CompositorD3D9::EnsureSize()
{
  LayoutDeviceIntRect rect;
  mWidget->GetClientBounds(rect);

  mSize = rect.Size();
}
Пример #6
0
void
ClientLayerManager::MakeSnapshotIfRequired()
{
  if (!mShadowTarget) {
    return;
  }
  if (mWidget) {
    if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) {
      // The compositor doesn't draw to a different sized surface
      // when there's a rotation. Instead we rotate the result
      // when drawing into dt
      LayoutDeviceIntRect outerBounds;
      mWidget->GetBounds(outerBounds);

      IntRect bounds = ToOutsideIntRect(mShadowTarget->GetClipExtents());
      if (mTargetRotation) {
        bounds =
          RotateRect(bounds, outerBounds.ToUnknownRect(), mTargetRotation);
      }

      SurfaceDescriptor inSnapshot;
      if (!bounds.IsEmpty() &&
          mForwarder->AllocSurfaceDescriptor(bounds.Size(),
                                             gfxContentType::COLOR_ALPHA,
                                             &inSnapshot)) {

        // Make a copy of |inSnapshot| because the call to send it over IPC
        // will call forget() on the Shmem inside, and zero it out.
        SurfaceDescriptor outSnapshot = inSnapshot;

        if (remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) {
          RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(outSnapshot);
          DrawTarget* dt = mShadowTarget->GetDrawTarget();

          Rect dstRect(bounds.x, bounds.y, bounds.width, bounds.height);
          Rect srcRect(0, 0, bounds.width, bounds.height);

          gfx::Matrix rotate =
            ComputeTransformForUnRotation(outerBounds.ToUnknownRect(),
                                          mTargetRotation);

          gfx::Matrix oldMatrix = dt->GetTransform();
          dt->SetTransform(rotate * oldMatrix);
          dt->DrawSurface(surf, dstRect, srcRect,
                          DrawSurfaceOptions(),
                          DrawOptions(1.0f, CompositionOp::OP_OVER));
          dt->SetTransform(oldMatrix);
        }
        mForwarder->DestroySurfaceDescriptor(&outSnapshot);
      }
    }
  }
  mShadowTarget = nullptr;
}
Пример #7
0
LayoutDeviceIntRect
ContentCache::TextRectArray::GetUnionRect(uint32_t aOffset,
                                          uint32_t aLength) const
{
  LayoutDeviceIntRect rect;
  if (!InRange(aOffset, aLength)) {
    return rect;
  }
  for (uint32_t i = 0; i < aLength; i++) {
    rect = rect.Union(mRects[aOffset - mStart + i]);
  }
  return rect;
}
Пример #8
0
bool
ContentCacheInParent::GetCaretRect(uint32_t aOffset,
                                   LayoutDeviceIntRect& aCaretRect) const
{
  MOZ_LOG(sContentCacheLog, LogLevel::Info,
    ("ContentCacheInParent: 0x%p GetCaretRect(aOffset=%u), "
     "mCaret={ mOffset=%u, mRect=%s, IsValid()=%s }, mTextRectArray={ "
     "mStart=%u, mRects.Length()=%u }, mSelection={ mAnchor=%u, mFocus=%u, "
     "mWritingMode=%s, mAnchorCharRect=%s, mFocusCharRect=%s }, "
     "mFirstCharRect=%s",
     this, aOffset, mCaret.mOffset, GetRectText(mCaret.mRect).get(),
     GetBoolName(mCaret.IsValid()), mTextRectArray.mStart,
     mTextRectArray.mRects.Length(), mSelection.mAnchor, mSelection.mFocus,
     GetWritingModeName(mSelection.mWritingMode).get(),
     GetRectText(mSelection.mAnchorCharRect).get(),
     GetRectText(mSelection.mFocusCharRect).get(),
     GetRectText(mFirstCharRect).get()));

  if (mCaret.IsValid() && mCaret.mOffset == aOffset) {
    aCaretRect = mCaret.mRect;
    return true;
  }

  // Guess caret rect from the text rect if it's stored.
  if (!GetTextRect(aOffset, aCaretRect)) {
    // There might be previous character rect in the cache.  If so, we can
    // guess the caret rect with it.
    if (!aOffset || !GetTextRect(aOffset - 1, aCaretRect)) {
      aCaretRect.SetEmpty();
      return false;
    }

    if (mSelection.mWritingMode.IsVertical()) {
      aCaretRect.y = aCaretRect.YMost();
    } else {
      // XXX bidi-unaware.
      aCaretRect.x = aCaretRect.XMost();
    }
  }

  // XXX This is not bidi aware because we don't cache each character's
  //     direction.  However, this is usually used by IME, so, assuming the
  //     character is in LRT context must not cause any problem.
  if (mSelection.mWritingMode.IsVertical()) {
    aCaretRect.height = mCaret.IsValid() ? mCaret.mRect.height : 1;
  } else {
    aCaretRect.width = mCaret.IsValid() ? mCaret.mRect.width : 1;
  }
  return true;
}
Пример #9
0
bool
ContentCacheInChild::QueryCharRect(nsIWidget* aWidget,
                                   uint32_t aOffset,
                                   LayoutDeviceIntRect& aCharRect) const
{
  aCharRect.SetEmpty();

  nsEventStatus status = nsEventStatus_eIgnore;
  WidgetQueryContentEvent textRect(true, NS_QUERY_TEXT_RECT, aWidget);
  textRect.InitForQueryTextRect(aOffset, 1);
  aWidget->DispatchEvent(&textRect, status);
  if (NS_WARN_IF(!textRect.mSucceeded)) {
    return false;
  }
  aCharRect = textRect.mReply.mRect;

  // Guarantee the rect is not empty.
  if (NS_WARN_IF(!aCharRect.height)) {
    aCharRect.height = 1;
  }
  if (NS_WARN_IF(!aCharRect.width)) {
    aCharRect.width = 1;
  }
  return true;
}
Пример #10
0
LayoutDeviceIntRect
ContentCache::TextRectArray::GetUnionRectAsFarAsPossible(
                               uint32_t aOffset,
                               uint32_t aLength) const
{
  LayoutDeviceIntRect rect;
  if (!IsOverlappingWith(aOffset, aLength)) {
    return rect;
  }
  uint32_t startOffset = std::max(aOffset, mStart);
  uint32_t endOffset = std::min(aOffset + aLength, EndOffset());
  for (uint32_t i = 0; i < endOffset - startOffset; i++) {
    rect = rect.Union(mRects[startOffset - mStart + i]);
  }
  return rect;
}
Пример #11
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;
}
Пример #12
0
bool
ContentCacheInParent::GetUnionTextRects(
                        uint32_t aOffset,
                        uint32_t aLength,
                        LayoutDeviceIntRect& aUnionTextRect) const
{
  MOZ_LOG(sContentCacheLog, LogLevel::Info,
    ("ContentCacheInParent: 0x%p GetUnionTextRects(aOffset=%u, "
     "aLength=%u), mTextRectArray={ mStart=%u, mRects.Length()=%u }, "
     "mSelection={ mAnchor=%u, mFocus=%u }",
     this, aOffset, aLength, mTextRectArray.mStart,
     mTextRectArray.mRects.Length(), mSelection.mAnchor, mSelection.mFocus));

  CheckedInt<uint32_t> endOffset =
    CheckedInt<uint32_t>(aOffset) + aLength;
  if (!endOffset.isValid()) {
    return false;
  }

  if (!mSelection.Collapsed() &&
      aOffset == mSelection.StartOffset() && aLength == mSelection.Length()) {
    NS_WARN_IF(mSelection.mRect.IsEmpty());
    aUnionTextRect = mSelection.mRect;
    return !aUnionTextRect.IsEmpty();
  }

  if (aLength == 1) {
    if (!aOffset) {
      NS_WARN_IF(mFirstCharRect.IsEmpty());
      aUnionTextRect = mFirstCharRect;
      return !aUnionTextRect.IsEmpty();
    }
    if (aOffset == mSelection.mAnchor) {
      NS_WARN_IF(mSelection.mAnchorCharRect.IsEmpty());
      aUnionTextRect = mSelection.mAnchorCharRect;
      return !aUnionTextRect.IsEmpty();
    }
    if (aOffset == mSelection.mFocus) {
      NS_WARN_IF(mSelection.mFocusCharRect.IsEmpty());
      aUnionTextRect = mSelection.mFocusCharRect;
      return !aUnionTextRect.IsEmpty();
    }
  }

  // Even if some text rects are not cached of the queried range,
  // we should return union rect when the first character's rect is cached
  // since the first character rect is important and the others are not so
  // in most cases.

  if (!aOffset && aOffset != mSelection.mAnchor &&
      aOffset != mSelection.mFocus && !mTextRectArray.InRange(aOffset)) {
    // The first character rect isn't cached.
    return false;
  }

  if (mTextRectArray.IsOverlappingWith(aOffset, aLength)) {
    aUnionTextRect =
      mTextRectArray.GetUnionRectAsFarAsPossible(aOffset, aLength);
  } else {
    aUnionTextRect.SetEmpty();
  }

  if (!aOffset) {
    aUnionTextRect = aUnionTextRect.Union(mFirstCharRect);
  }
  if (aOffset <= mSelection.mAnchor && mSelection.mAnchor < endOffset.value()) {
    aUnionTextRect = aUnionTextRect.Union(mSelection.mAnchorCharRect);
  }
  if (aOffset <= mSelection.mFocus && mSelection.mFocus < endOffset.value()) {
    aUnionTextRect = aUnionTextRect.Union(mSelection.mFocusCharRect);
  }
  return !aUnionTextRect.IsEmpty();
}
Пример #13
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);
    }
  }
}
Пример #14
0
NS_METHOD
PuppetWidget::GetScreenBounds(LayoutDeviceIntRect& aRect) {
  aRect.MoveTo(WidgetToScreenOffset());
  aRect.SizeTo(LayoutDeviceIntSize::FromUnknownSize(mBounds.Size()));
  return NS_OK;
}
Пример #15
0
void
ClientLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
{
  mInTransaction = true;
  mTransactionStart = TimeStamp::Now();

#ifdef MOZ_LAYERS_HAVE_LOG
  MOZ_LAYERS_LOG(("[----- BeginTransaction"));
  Log();
#endif

  NS_ASSERTION(!InTransaction(), "Nested transactions not allowed");
  mPhase = PHASE_CONSTRUCTION;

  MOZ_ASSERT(mKeepAlive.IsEmpty(), "uncommitted txn?");
  RefPtr<gfxContext> targetContext = aTarget;

  // If the last transaction was incomplete (a failed DoEmptyTransaction),
  // don't signal a new transaction to ShadowLayerForwarder. Carry on adding
  // to the previous transaction.
  dom::ScreenOrientationInternal orientation;
  if (dom::TabChild* window = mWidget->GetOwningTabChild()) {
    orientation = window->GetOrientation();
  } else {
    hal::ScreenConfiguration currentConfig;
    hal::GetCurrentScreenConfiguration(&currentConfig);
    orientation = currentConfig.orientation();
  }
  LayoutDeviceIntRect targetBounds = mWidget->GetNaturalBounds();
  targetBounds.x = targetBounds.y = 0;
  mForwarder->BeginTransaction(targetBounds.ToUnknownRect(), mTargetRotation,
                               orientation);

  // If we're drawing on behalf of a context with async pan/zoom
  // enabled, then the entire buffer of painted layers might be
  // composited (including resampling) asynchronously before we get
  // a chance to repaint, so we have to ensure that it's all valid
  // and not rotated.
  //
  // Desktop does not support async zoom yet, so we ignore this for those
  // platforms.
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_UIKIT)
  if (mWidget && mWidget->GetOwningTabChild()) {
    mCompositorMightResample = AsyncPanZoomEnabled();
  }
#endif

  // If we have a non-default target, we need to let our shadow manager draw
  // to it. This will happen at the end of the transaction.
  if (aTarget && XRE_IsParentProcess()) {
    mShadowTarget = aTarget;
  } else {
    NS_ASSERTION(!aTarget,
                 "Content-process ClientLayerManager::BeginTransactionWithTarget not supported");
  }

  // If this is a new paint, increment the paint sequence number.
  if (!mIsRepeatTransaction) {
    // Increment the paint sequence number even if test logging isn't
    // enabled in this process; it may be enabled in the parent process,
    // and the parent process expects unique sequence numbers.
    ++mPaintSequenceNumber;
    if (gfxPrefs::APZTestLoggingEnabled()) {
      mApzTestData.StartNewPaint(mPaintSequenceNumber);
    }
  }
}
Пример #16
0
bool
ClientLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
{
  // Wait for any previous async paints to complete before starting to paint again.
  GetCompositorBridgeChild()->FlushAsyncPaints();

  MOZ_ASSERT(mForwarder, "ClientLayerManager::BeginTransaction without forwarder");
  if (!mForwarder->IPCOpen()) {
    gfxCriticalNote << "ClientLayerManager::BeginTransaction with IPC channel down. GPU process may have died.";
    return false;
  }

  if (XRE_IsContentProcess() &&
      mForwarder->DeviceCanReset() &&
      mDeviceResetSequenceNumber != CompositorBridgeChild::Get()->DeviceResetSequenceNumber())
  {
    // The compositor has informed this process that a device reset occurred,
    // but it has not finished informing each TabChild of its new
    // TextureFactoryIdentifier. Until then, it's illegal to paint. Note that
    // it is also illegal to request a new TIF synchronously, because we're
    // not guaranteed the UI process has finished acquiring new compositors
    // for each widget.
    //
    // Note that we only do this for accelerated backends, since we do not
    // perform resets on basic compositors.
    gfxCriticalNote << "Discarding a paint since a device reset has not yet been acknowledged.";
    return false;
  }

  mInTransaction = true;
  mTransactionStart = TimeStamp::Now();

#ifdef MOZ_LAYERS_HAVE_LOG
  MOZ_LAYERS_LOG(("[----- BeginTransaction"));
  Log();
#endif

  NS_ASSERTION(!InTransaction(), "Nested transactions not allowed");
  mPhase = PHASE_CONSTRUCTION;

  MOZ_ASSERT(mKeepAlive.IsEmpty(), "uncommitted txn?");

  // If the last transaction was incomplete (a failed DoEmptyTransaction),
  // don't signal a new transaction to ShadowLayerForwarder. Carry on adding
  // to the previous transaction.
  dom::ScreenOrientationInternal orientation;
  if (dom::TabChild* window = mWidget->GetOwningTabChild()) {
    orientation = window->GetOrientation();
  } else {
    hal::ScreenConfiguration currentConfig;
    hal::GetCurrentScreenConfiguration(&currentConfig);
    orientation = currentConfig.orientation();
  }
  LayoutDeviceIntRect targetBounds = mWidget->GetNaturalBounds();
  targetBounds.x = targetBounds.y = 0;
  mForwarder->BeginTransaction(targetBounds.ToUnknownRect(), mTargetRotation,
                               orientation);

  // If we're drawing on behalf of a context with async pan/zoom
  // enabled, then the entire buffer of painted layers might be
  // composited (including resampling) asynchronously before we get
  // a chance to repaint, so we have to ensure that it's all valid
  // and not rotated.
  //
  // Desktop does not support async zoom yet, so we ignore this for those
  // platforms.
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT)
  if (mWidget && mWidget->GetOwningTabChild()) {
    mCompositorMightResample = AsyncPanZoomEnabled();
  }
#endif

  // If we have a non-default target, we need to let our shadow manager draw
  // to it. This will happen at the end of the transaction.
  if (aTarget && XRE_IsParentProcess()) {
    mShadowTarget = aTarget;
  } else {
    NS_ASSERTION(!aTarget,
                 "Content-process ClientLayerManager::BeginTransactionWithTarget not supported");
  }

  // If this is a new paint, increment the paint sequence number.
  if (!mIsRepeatTransaction) {
    // Increment the paint sequence number even if test logging isn't
    // enabled in this process; it may be enabled in the parent process,
    // and the parent process expects unique sequence numbers.
    ++mPaintSequenceNumber;
    if (gfxPrefs::APZTestLoggingEnabled()) {
      mApzTestData.StartNewPaint(mPaintSequenceNumber);
    }
  }
  return true;
}
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);
  }
}
Пример #18
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);
  }
}
Пример #19
0
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;
}
Пример #20
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;
}
Пример #21
0
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;
}