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:
Andrew Osmond 2018-08-08 07:56:01 -04:00
Родитель 24a33b307e
Коммит 4392634285
2 изменённых файлов: 69 добавлений и 22 удалений

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

@ -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__