Bug 721659. Update the width/height of an image synchronously when src is set to something that was preloaded. r=bholley

This commit is contained in:
Boris Zbarsky 2012-03-19 18:22:02 -04:00
Родитель 187666328d
Коммит 21f5f2e536
12 изменённых файлов: 154 добавлений и 38 удалений

Просмотреть файл

@ -61,6 +61,7 @@
#include "nsNetUtil.h" #include "nsNetUtil.h"
#include "nsAsyncDOMEvent.h" #include "nsAsyncDOMEvent.h"
#include "nsGenericElement.h" #include "nsGenericElement.h"
#include "nsImageFrame.h"
#include "nsIPresShell.h" #include "nsIPresShell.h"
#include "nsEventStates.h" #include "nsEventStates.h"
@ -300,10 +301,7 @@ nsImageLoadingContent::OnStopDecode(imgIRequest* aRequest,
// If the pending request is loaded, switch to it. // If the pending request is loaded, switch to it.
if (aRequest == mPendingRequest) { if (aRequest == mPendingRequest) {
PrepareCurrentRequest() = mPendingRequest; MakePendingRequestCurrent();
mPendingRequest = nsnull;
mCurrentRequestNeedsResetAnimation = mPendingRequestNeedsResetAnimation;
mPendingRequestNeedsResetAnimation = false;
} }
NS_ABORT_IF_FALSE(aRequest == mCurrentRequest, NS_ABORT_IF_FALSE(aRequest == mCurrentRequest,
"One way or another, we should be current by now"); "One way or another, we should be current by now");
@ -792,6 +790,26 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
getter_AddRefs(req)); getter_AddRefs(req));
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
TrackImage(req); TrackImage(req);
// Handle cases when we just ended up with a pending request but it's
// already done. In that situation we have to synchronously switch that
// request to being the current request, because websites depend on that
// behavior.
if (req == mPendingRequest) {
PRUint32 pendingLoadStatus;
rv = req->GetImageStatus(&pendingLoadStatus);
if (NS_SUCCEEDED(rv) &&
(pendingLoadStatus & imgIRequest::STATUS_LOAD_COMPLETE)) {
MakePendingRequestCurrent();
MOZ_ASSERT(mCurrentRequest,
"How could we not have a current request here?");
nsImageFrame *f = do_QueryFrame(GetOurPrimaryFrame());
if (f) {
f->NotifyNewCurrentRequest(mCurrentRequest, NS_OK);
}
}
}
} else { } else {
// If we don't have a current URI, we might as well store this URI so people // If we don't have a current URI, we might as well store this URI so people
// know what we tried (and failed) to load. // know what we tried (and failed) to load.
@ -1046,6 +1064,16 @@ nsImageLoadingContent::PreparePendingRequest()
return mPendingRequest; return mPendingRequest;
} }
void
nsImageLoadingContent::MakePendingRequestCurrent()
{
MOZ_ASSERT(mPendingRequest);
PrepareCurrentRequest() = mPendingRequest;
mPendingRequest = nsnull;
mCurrentRequestNeedsResetAnimation = mPendingRequestNeedsResetAnimation;
mPendingRequestNeedsResetAnimation = false;
}
void void
nsImageLoadingContent::ClearCurrentRequest(nsresult aReason) nsImageLoadingContent::ClearCurrentRequest(nsresult aReason)
{ {

Просмотреть файл

@ -297,6 +297,12 @@ protected:
nsCOMPtr<imgIRequest>& PrepareCurrentRequest(); nsCOMPtr<imgIRequest>& PrepareCurrentRequest();
nsCOMPtr<imgIRequest>& PreparePendingRequest(); nsCOMPtr<imgIRequest>& PreparePendingRequest();
/**
* Switch our pending request to be our current request.
* mPendingRequest must be non-null!
*/
void MakePendingRequestCurrent();
/** /**
* Cancels and nulls-out the "current" and "pending" requests if they exist. * Cancels and nulls-out the "current" and "pending" requests if they exist.
*/ */

Просмотреть файл

@ -642,10 +642,6 @@ nsImageFrame::OnStopDecode(imgIRequest *aRequest,
nsresult aStatus, nsresult aStatus,
const PRUnichar *aStatusArg) const PRUnichar *aStatusArg)
{ {
nsPresContext *presContext = PresContext();
nsIPresShell *presShell = presContext->GetPresShell();
NS_ASSERTION(presShell, "No PresShell.");
// Check what request type we're dealing with // Check what request type we're dealing with
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent); nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
NS_ASSERTION(imageLoader, "Who's notifying us??"); NS_ASSERTION(imageLoader, "Who's notifying us??");
@ -657,41 +653,49 @@ nsImageFrame::OnStopDecode(imgIRequest *aRequest,
} }
if (loadType == nsIImageLoadingContent::PENDING_REQUEST) { if (loadType == nsIImageLoadingContent::PENDING_REQUEST) {
// May have to switch sizes here! NotifyNewCurrentRequest(aRequest, aStatus);
bool intrinsicSizeChanged = true;
if (NS_SUCCEEDED(aStatus)) {
nsCOMPtr<imgIContainer> imageContainer;
aRequest->GetImage(getter_AddRefs(imageContainer));
NS_ASSERTION(imageContainer, "Successful load with no container?");
intrinsicSizeChanged = UpdateIntrinsicSize(imageContainer);
intrinsicSizeChanged = UpdateIntrinsicRatio(imageContainer) ||
intrinsicSizeChanged;
}
else {
// Have to size to 0,0 so that GetDesiredSize recalculates the size
mIntrinsicSize.width.SetCoordValue(0);
mIntrinsicSize.height.SetCoordValue(0);
mIntrinsicRatio.SizeTo(0, 0);
}
if (mState & IMAGE_GOTINITIALREFLOW) { // do nothing if we haven't gotten the initial reflow yet
if (!(mState & IMAGE_SIZECONSTRAINED) && intrinsicSizeChanged) {
if (presShell) {
presShell->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
NS_FRAME_IS_DIRTY);
}
} else {
nsSize s = GetSize();
nsRect r(0, 0, s.width, s.height);
// Update border+content to account for image change
Invalidate(r);
}
}
} }
return NS_OK; return NS_OK;
} }
void
nsImageFrame::NotifyNewCurrentRequest(imgIRequest *aRequest,
nsresult aStatus)
{
// May have to switch sizes here!
bool intrinsicSizeChanged = true;
if (NS_SUCCEEDED(aStatus)) {
nsCOMPtr<imgIContainer> imageContainer;
aRequest->GetImage(getter_AddRefs(imageContainer));
NS_ASSERTION(imageContainer, "Successful load with no container?");
intrinsicSizeChanged = UpdateIntrinsicSize(imageContainer);
intrinsicSizeChanged = UpdateIntrinsicRatio(imageContainer) ||
intrinsicSizeChanged;
}
else {
// Have to size to 0,0 so that GetDesiredSize recalculates the size
mIntrinsicSize.width.SetCoordValue(0);
mIntrinsicSize.height.SetCoordValue(0);
mIntrinsicRatio.SizeTo(0, 0);
}
if (mState & IMAGE_GOTINITIALREFLOW) { // do nothing if we haven't gotten the initial reflow yet
if (!(mState & IMAGE_SIZECONSTRAINED) && intrinsicSizeChanged) {
nsIPresShell *presShell = PresContext()->GetPresShell();
if (presShell) {
presShell->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
NS_FRAME_IS_DIRTY);
}
} else {
nsSize s = GetSize();
nsRect r(0, 0, s.width, s.height);
// Update border+content to account for image change
Invalidate(r);
}
}
}
nsresult nsresult
nsImageFrame::FrameChanged(imgIRequest *aRequest, nsImageFrame::FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer, imgIContainer *aContainer,

Просмотреть файл

@ -62,6 +62,7 @@ class nsDisplayImage;
class nsPresContext; class nsPresContext;
class nsImageFrame; class nsImageFrame;
class nsTransform2D; class nsTransform2D;
class nsImageLoadingContent;
namespace mozilla { namespace mozilla {
namespace layers { namespace layers {
@ -250,6 +251,7 @@ protected:
protected: protected:
friend class nsImageListener; friend class nsImageListener;
friend class nsImageLoadingContent;
nsresult OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage); nsresult OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
nsresult OnDataAvailable(imgIRequest *aRequest, bool aCurrentFrame, nsresult OnDataAvailable(imgIRequest *aRequest, bool aCurrentFrame,
const nsIntRect *rect); const nsIntRect *rect);
@ -259,6 +261,10 @@ protected:
nsresult FrameChanged(imgIRequest *aRequest, nsresult FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer, imgIContainer *aContainer,
const nsIntRect *aDirtyRect); const nsIntRect *aDirtyRect);
/**
* Notification that aRequest will now be the current request.
*/
void NotifyNewCurrentRequest(imgIRequest *aRequest, nsresult aStatus);
private: private:
// random helpers // random helpers

Двоичные данные
layout/reftests/image/blue-16x20.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 118 B

Двоичные данные
layout/reftests/image/blue-32x32.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 110 B

Просмотреть файл

@ -3,3 +3,7 @@
== image-zoom-1.html image-zoom-1-ref.html == image-zoom-1.html image-zoom-1-ref.html
== image-zoom-2.html image-zoom-1-ref.html == image-zoom-2.html image-zoom-1-ref.html
== invalid-url-image-1.html invalid-url-image-1-ref.html == invalid-url-image-1.html invalid-url-image-1-ref.html
== sync-image-switch-1a.html sync-image-switch-1-ref.html
== sync-image-switch-1b.html sync-image-switch-1-ref.html
== sync-image-switch-1c.html sync-image-switch-1-ref.html
== sync-image-switch-1d.html sync-image-switch-1-ref.html

Просмотреть файл

@ -0,0 +1,4 @@
<!DOCTYPE html>
<html>
<img src="blue-32x32.png">
</html>

Просмотреть файл

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html class="reftest-wait">
<img src="blue-16x20.png">
<script>
var otherImageSrc = "blue-32x32.png"
window.onload = function() {
var img = document.querySelector("img");
img.src = otherImageSrc;
img.style.width = img.naturalWidth + "px";
img.style.height = img.naturalHeight + "px";
document.documentElement.className = "";
}
var otherImage = new Image;
otherImage.src = otherImageSrc;
</script>
</html>

Просмотреть файл

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html class="reftest-wait">
<img src="blue-16x20.png">
<script>
var otherImageSrc = "blue-32x32.png"
window.onload = function() {
var img = document.querySelector("img");
img.src = otherImageSrc;
img.style.width = img.width + "px";
img.style.height = img.height + "px";
document.documentElement.className = "";
}
var otherImage = new Image;
otherImage.src = otherImageSrc;
</script>
</html>

Просмотреть файл

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html class="reftest-wait">
<input type="image" src="blue-16x20.png">
<script>
var otherImageSrc = "blue-32x32.png"
window.onload = function() {
var img = document.querySelector("input");
img.src = otherImageSrc;
img.style.width = img.naturalWidth + "px";
img.style.height = img.naturalHeight + "px";
document.documentElement.className = "";
}
var otherImage = new Image;
otherImage.src = otherImageSrc;
</script>
</html>

Просмотреть файл

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html class="reftest-wait">
<input type="image" src="blue-16x20.png">
<script>
var otherImageSrc = "blue-32x32.png"
window.onload = function() {
var img = document.querySelector("input");
img.src = otherImageSrc;
img.style.width = img.width + "px";
img.style.height = img.height + "px";
document.documentElement.className = "";
}
var otherImage = new Image;
otherImage.src = otherImageSrc;
</script>
</html>