зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1416328 - Part 1. Add configurable synchronous decoding hint to nsImageLoadingContent. r=tnikkel
The next part in this series depends on this to implement the HTMLImageElement's decoding attribute. This functionality allows the caller to force an nsImageLoadingContent and its associated nsImageFrame and nsSVGImageFrame objects to synchronously decode an image at draw time. It will only synchronously decode if it has completed metadata decoding (i.e. knows its size) and has received all of the encoded data; this mirrors the load event criteria for an image.
This commit is contained in:
Родитель
24a33b307e
Коммит
4392634285
|
@ -99,7 +99,8 @@ nsImageLoadingContent::nsImageLoadingContent()
|
|||
mStateChangerDepth(0),
|
||||
mCurrentRequestRegistered(false),
|
||||
mPendingRequestRegistered(false),
|
||||
mIsStartingImageLoad(false)
|
||||
mIsStartingImageLoad(false),
|
||||
mSyncDecodingHint(false)
|
||||
{
|
||||
if (!nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) {
|
||||
mLoadingEnabled = false;
|
||||
|
@ -335,6 +336,50 @@ nsImageLoadingContent::SetLoadingEnabled(bool aLoadingEnabled)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsImageLoadingContent::SetSyncDecodingHint(bool aHint)
|
||||
{
|
||||
if (mSyncDecodingHint == aHint) {
|
||||
return;
|
||||
}
|
||||
|
||||
mSyncDecodingHint = aHint;
|
||||
MaybeForceSyncDecoding(/* aPrepareNextRequest */ false);
|
||||
}
|
||||
|
||||
void
|
||||
nsImageLoadingContent::MaybeForceSyncDecoding(bool aPrepareNextRequest,
|
||||
nsIFrame* aFrame /* = nullptr */)
|
||||
{
|
||||
nsIFrame* frame = aFrame ? aFrame : GetOurPrimaryFrame();
|
||||
nsImageFrame* imageFrame = do_QueryFrame(frame);
|
||||
nsSVGImageFrame* svgImageFrame = do_QueryFrame(frame);
|
||||
if (!imageFrame && !svgImageFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool forceSync = mSyncDecodingHint;
|
||||
if (!forceSync && aPrepareNextRequest) {
|
||||
// Detect JavaScript-based animations created by changing the |src|
|
||||
// attribute on a timer.
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
TimeDuration threshold =
|
||||
TimeDuration::FromMilliseconds(
|
||||
gfxPrefs::ImageInferSrcAnimationThresholdMS());
|
||||
|
||||
// If the length of time between request changes is less than the threshold,
|
||||
// then force sync decoding to eliminate flicker from the animation.
|
||||
forceSync = (now - mMostRecentRequestChange < threshold);
|
||||
mMostRecentRequestChange = now;
|
||||
}
|
||||
|
||||
if (imageFrame) {
|
||||
imageFrame->SetForceSyncDecoding(forceSync);
|
||||
} else {
|
||||
svgImageFrame->SetForceSyncDecoding(forceSync);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsImageLoadingContent::GetImageBlockingStatus(int16_t* aStatus)
|
||||
{
|
||||
|
@ -629,6 +674,7 @@ nsImageLoadingContent::FrameCreated(nsIFrame* aFrame)
|
|||
{
|
||||
NS_ASSERTION(aFrame, "aFrame is null");
|
||||
|
||||
MaybeForceSyncDecoding(/* aPrepareNextRequest */ false, aFrame);
|
||||
TrackImage(mCurrentRequest, aFrame);
|
||||
TrackImage(mPendingRequest, aFrame);
|
||||
|
||||
|
@ -1263,27 +1309,7 @@ nsImageLoadingContent::CancelPendingEvent()
|
|||
RefPtr<imgRequestProxy>&
|
||||
nsImageLoadingContent::PrepareNextRequest(ImageLoadType aImageLoadType)
|
||||
{
|
||||
nsImageFrame* imageFrame = do_QueryFrame(GetOurPrimaryFrame());
|
||||
nsSVGImageFrame* svgImageFrame = do_QueryFrame(GetOurPrimaryFrame());
|
||||
if (imageFrame || svgImageFrame) {
|
||||
// Detect JavaScript-based animations created by changing the |src|
|
||||
// attribute on a timer.
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
TimeDuration threshold =
|
||||
TimeDuration::FromMilliseconds(
|
||||
gfxPrefs::ImageInferSrcAnimationThresholdMS());
|
||||
|
||||
// If the length of time between request changes is less than the threshold,
|
||||
// then force sync decoding to eliminate flicker from the animation.
|
||||
bool forceSync = (now - mMostRecentRequestChange < threshold);
|
||||
if (imageFrame) {
|
||||
imageFrame->SetForceSyncDecoding(forceSync);
|
||||
} else {
|
||||
svgImageFrame->SetForceSyncDecoding(forceSync);
|
||||
}
|
||||
|
||||
mMostRecentRequestChange = now;
|
||||
}
|
||||
MaybeForceSyncDecoding(/* aPrepareNextRequest */ true);
|
||||
|
||||
// We only want to cancel the existing current request if size is not
|
||||
// available. bz says the web depends on this behavior.
|
||||
|
|
|
@ -80,6 +80,11 @@ public:
|
|||
|
||||
mozilla::dom::Element* FindImageMap();
|
||||
|
||||
/**
|
||||
* Toggle whether or not to synchronously decode an image on draw.
|
||||
*/
|
||||
void SetSyncDecodingHint(bool aHint);
|
||||
|
||||
protected:
|
||||
enum ImageLoadType {
|
||||
// Most normal image loads
|
||||
|
@ -443,6 +448,19 @@ private:
|
|||
*/
|
||||
void MakePendingScriptedRequestsCurrent();
|
||||
|
||||
/**
|
||||
* Depending on the configured decoding hint, and/or how recently we updated
|
||||
* the image request, force or stop the frame from decoding the image
|
||||
* synchronously when it is drawn.
|
||||
* @param aPrepareNextRequest True if this is when updating the image request.
|
||||
* @param aFrame If called from FrameCreated the frame passed to FrameCreated.
|
||||
* This is our frame, but at the time of the FrameCreated call
|
||||
* our primary frame pointer hasn't been set yet, so this is
|
||||
* only way to get our frame.
|
||||
*/
|
||||
void MaybeForceSyncDecoding(bool aPrepareNextRequest,
|
||||
nsIFrame* aFrame = nullptr);
|
||||
|
||||
/**
|
||||
* Typically we will have only one observer (our frame in the screen
|
||||
* prescontext), so we want to only make space for one and to
|
||||
|
@ -522,6 +540,9 @@ private:
|
|||
//
|
||||
// Also we use this variable to check if some evil code is reentering LoadImage.
|
||||
bool mIsStartingImageLoad;
|
||||
|
||||
// If true, force frames to synchronously decode images on draw.
|
||||
bool mSyncDecodingHint;
|
||||
};
|
||||
|
||||
#endif // nsImageLoadingContent_h__
|
||||
|
|
Загрузка…
Ссылка в новой задаче