mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Bug 1151359 (Part 1) - Predict the size of nsImageFrame images before drawing. r=tn
This commit is contained in:
parent
7b3c3fd488
commit
faeeebcacd
@ -1512,6 +1512,15 @@ nsImageLoadingContent::TrackImage(imgIRequest* aImage)
|
||||
nsIDocument* doc = GetOurCurrentDoc();
|
||||
if (doc && (mFrameCreateCalled || GetOurPrimaryFrame()) &&
|
||||
(mVisibleCount > 0)) {
|
||||
|
||||
if (mVisibleCount == 1) {
|
||||
// Since we're becoming visible, request a decode.
|
||||
nsImageFrame* f = do_QueryFrame(GetOurPrimaryFrame());
|
||||
if (f) {
|
||||
f->MaybeDecodeForPredictedSize();
|
||||
}
|
||||
}
|
||||
|
||||
if (aImage == mCurrentRequest && !(mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
|
||||
mCurrentRequestFlags |= REQUEST_IS_TRACKED;
|
||||
doc->AddImage(mCurrentRequest);
|
||||
|
@ -373,6 +373,10 @@ struct RenderTargetPixel {
|
||||
* generally be represented in ScreenPixel units.
|
||||
*/
|
||||
struct ScreenPixel {
|
||||
static nsIntSize ToUntyped(const ScreenIntSize& aSize) {
|
||||
return nsIntSize(aSize.width, aSize.height);
|
||||
}
|
||||
|
||||
static ScreenIntPoint FromUntyped(const nsIntPoint& aPoint) {
|
||||
return ScreenIntPoint(aPoint.x, aPoint.y);
|
||||
}
|
||||
|
@ -577,6 +577,10 @@ nsImageFrame::OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage)
|
||||
presShell->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
|
||||
NS_FRAME_IS_DIRTY);
|
||||
}
|
||||
} else {
|
||||
// We've already gotten the initial reflow, and our size hasn't changed,
|
||||
// so we're ready to request a decode.
|
||||
MaybeDecodeForPredictedSize();
|
||||
}
|
||||
}
|
||||
|
||||
@ -682,12 +686,93 @@ nsImageFrame::NotifyNewCurrentRequest(imgIRequest *aRequest,
|
||||
presShell->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
|
||||
NS_FRAME_IS_DIRTY);
|
||||
}
|
||||
} else {
|
||||
// We've already gotten the initial reflow, and our size hasn't changed,
|
||||
// so we're ready to request a decode.
|
||||
MaybeDecodeForPredictedSize();
|
||||
}
|
||||
// Update border+content to account for image change
|
||||
InvalidateFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsImageFrame::MaybeDecodeForPredictedSize()
|
||||
{
|
||||
// Check that we're ready to decode.
|
||||
if (!mImage) {
|
||||
return; // Nothing to do yet.
|
||||
}
|
||||
|
||||
if (mComputedSize.IsEmpty()) {
|
||||
return; // We won't draw anything, so no point in decoding.
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
|
||||
MOZ_ASSERT(imageLoader);
|
||||
if (imageLoader->GetVisibleCount() == 0) {
|
||||
return; // We're not visible, so don't decode.
|
||||
}
|
||||
|
||||
// OK, we're ready to decode. Compute the scale to the screen...
|
||||
nsIPresShell* presShell = PresContext()->GetPresShell();
|
||||
LayoutDeviceToScreenScale2D resolutionToScreen(
|
||||
presShell->GetCumulativeResolution()
|
||||
* nsLayoutUtils::GetTransformToAncestorScale(this));
|
||||
|
||||
// ...and this frame's content box...
|
||||
const nsPoint offset =
|
||||
GetOffsetToCrossDoc(nsLayoutUtils::GetReferenceFrame(this));
|
||||
const nsRect frameContentBox = GetInnerArea() + offset;
|
||||
|
||||
// ...and our predicted dest rect...
|
||||
const int32_t factor = PresContext()->AppUnitsPerDevPixel();
|
||||
const LayoutDeviceRect destRect =
|
||||
LayoutDeviceRect::FromAppUnits(PredictedDestRect(frameContentBox), factor);
|
||||
|
||||
// ...and use them to compute our predicted size in screen pixels.
|
||||
const ScreenSize predictedScreenSize = destRect.Size() * resolutionToScreen;
|
||||
const ScreenIntSize predictedScreenIntSize = RoundedToInt(predictedScreenSize);
|
||||
if (predictedScreenIntSize.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine the optimal image size to use.
|
||||
uint32_t flags = imgIContainer::FLAG_HIGH_QUALITY_SCALING
|
||||
| imgIContainer::FLAG_ASYNC_NOTIFY;
|
||||
GraphicsFilter filter = nsLayoutUtils::GetGraphicsFilterForFrame(this);
|
||||
gfxSize gfxPredictedScreenSize = gfxSize(predictedScreenIntSize.width,
|
||||
predictedScreenIntSize.height);
|
||||
nsIntSize predictedImageSize =
|
||||
mImage->OptimalImageSizeForDest(gfxPredictedScreenSize,
|
||||
imgIContainer::FRAME_CURRENT,
|
||||
filter, flags);
|
||||
|
||||
// Request a decode.
|
||||
mImage->RequestDecodeForSize(predictedImageSize, flags);
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsImageFrame::PredictedDestRect(const nsRect& aFrameContentBox)
|
||||
{
|
||||
// What is the rect painted by the image? It's the image's "dest rect" (the
|
||||
// rect where a full copy of the image is mapped), clipped to the container's
|
||||
// content box. So, we intersect those rects.
|
||||
|
||||
// Note: To get the "dest rect", we have to provide the "constraint rect"
|
||||
// (which is the content-box, with the effects of fragmentation undone).
|
||||
nsRect constraintRect(aFrameContentBox.TopLeft(), mComputedSize);
|
||||
constraintRect.y -= GetContinuationOffset();
|
||||
|
||||
const nsRect destRect =
|
||||
nsLayoutUtils::ComputeObjectDestRect(constraintRect,
|
||||
mIntrinsicSize,
|
||||
mIntrinsicRatio,
|
||||
StylePosition());
|
||||
|
||||
return destRect.Intersect(aFrameContentBox);
|
||||
}
|
||||
|
||||
void
|
||||
nsImageFrame::EnsureIntrinsicSizeAndRatio()
|
||||
{
|
||||
@ -935,6 +1020,10 @@ nsImageFrame::Reflow(nsPresContext* aPresContext,
|
||||
static_assert(eOverflowType_LENGTH == 2, "Unknown overflow types?");
|
||||
nsRect& visualOverflow = aMetrics.VisualOverflow();
|
||||
visualOverflow.UnionRect(visualOverflow, altFeedbackSize);
|
||||
} else {
|
||||
// We've just reflowed and we should have an accurate size, so we're ready
|
||||
// to request a decode.
|
||||
MaybeDecodeForPredictedSize();
|
||||
}
|
||||
FinishAndStoreOverflow(&aMetrics);
|
||||
|
||||
@ -1475,30 +1564,14 @@ nsDisplayImage::GetContainer(LayerManager* aManager,
|
||||
nsRect
|
||||
nsDisplayImage::GetDestRect(bool* aSnap)
|
||||
{
|
||||
// OK, we want to return the entire region painted by the image. But what is
|
||||
// that region? It's the image's "dest rect" (the rect where a full copy of
|
||||
// the image is mapped), clipped to the container's content box (which is what
|
||||
// GetBounds() returns). So, we grab those rects and intersect them.
|
||||
bool snap = true;
|
||||
const nsRect frameContentBox = GetBounds(&snap);
|
||||
if (aSnap) {
|
||||
*aSnap = snap;
|
||||
}
|
||||
|
||||
// Note: To get the "dest rect", we have to provide the "constraint rect"
|
||||
// (which is the content-box, with the effects of fragmentation undone).
|
||||
nsImageFrame* imageFrame = static_cast<nsImageFrame*>(mFrame);
|
||||
nsRect constraintRect(frameContentBox.TopLeft(),
|
||||
imageFrame->mComputedSize);
|
||||
constraintRect.y -= imageFrame->GetContinuationOffset();
|
||||
|
||||
const nsRect destRect =
|
||||
nsLayoutUtils::ComputeObjectDestRect(constraintRect,
|
||||
imageFrame->mIntrinsicSize,
|
||||
imageFrame->mIntrinsicRatio,
|
||||
imageFrame->StylePosition());
|
||||
|
||||
return destRect.Intersect(frameContentBox);
|
||||
return imageFrame->PredictedDestRect(frameContentBox);
|
||||
}
|
||||
|
||||
LayerState
|
||||
|
@ -219,6 +219,14 @@ protected:
|
||||
const nsRect& aDirtyRect, imgIContainer* aImage,
|
||||
uint32_t aFlags);
|
||||
|
||||
/**
|
||||
* If we're ready to decode - that is, if our current request's image is
|
||||
* available and our decoding heuristics are satisfied - then trigger a decode
|
||||
* for our image at the size we predict it will be drawn next time it's
|
||||
* painted.
|
||||
*/
|
||||
void MaybeDecodeForPredictedSize();
|
||||
|
||||
protected:
|
||||
friend class nsImageListener;
|
||||
friend class nsImageLoadingContent;
|
||||
@ -235,6 +243,13 @@ protected:
|
||||
/// Always sync decode our image when painting if @aForce is true.
|
||||
void SetForceSyncDecoding(bool aForce) { mForceSyncDecoding = aForce; }
|
||||
|
||||
/**
|
||||
* Computes the predicted dest rect that we'll draw into, in app units, based
|
||||
* upon the provided frame content box. (The content box is what
|
||||
* nsDisplayImage::GetBounds() returns.)
|
||||
*/
|
||||
nsRect PredictedDestRect(const nsRect& aFrameContentBox);
|
||||
|
||||
private:
|
||||
// random helpers
|
||||
inline void SpecToURI(const nsAString& aSpec, nsIIOService *aIOService,
|
||||
|
Loading…
Reference in New Issue
Block a user