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