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;
}
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();
}
Exemple #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);
  }
}
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);
  }
}
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();
}