Backed out changeset c9f4dd3ed78b (bug 1606628) for causing failures in ImageLoader.cpp

CLOSED TREE
This commit is contained in:
Mihai Alexandru Michis 2020-02-06 23:19:55 +02:00
Родитель 77c6b3e983
Коммит 823e8c21f1
18 изменённых файлов: 766 добавлений и 420 удалений

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

@ -56,6 +56,7 @@ class ImageTracker {
void SetAnimatingState(bool aAnimating); void SetAnimatingState(bool aAnimating);
void RequestDiscardAll(); void RequestDiscardAll();
void MediaFeatureValuesChangedAllDocuments(const MediaFeatureChange&); void MediaFeatureValuesChangedAllDocuments(const MediaFeatureChange&);
private: private:

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

@ -1525,6 +1525,7 @@ void nsPresContext::MediaFeatureValuesChangedAllDocuments(
// Propagate the media feature value change down to any SVG images the // Propagate the media feature value change down to any SVG images the
// document is using. // document is using.
mDocument->StyleImageLoader()->MediaFeatureValuesChangedAllDocuments(aChange);
mDocument->ImageTracker()->MediaFeatureValuesChangedAllDocuments(aChange); mDocument->ImageTracker()->MediaFeatureValuesChangedAllDocuments(aChange);
// And then into any subdocuments. // And then into any subdocuments.

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

@ -17,7 +17,6 @@
#include "mozilla/ComputedStyle.h" #include "mozilla/ComputedStyle.h"
#include "mozilla/DebugOnly.h" #include "mozilla/DebugOnly.h"
#include "mozilla/dom/ElementInlines.h" #include "mozilla/dom/ElementInlines.h"
#include "mozilla/dom/ImageTracker.h"
#include "mozilla/dom/Selection.h" #include "mozilla/dom/Selection.h"
#include "mozilla/gfx/2D.h" #include "mozilla/gfx/2D.h"
#include "mozilla/gfx/gfxVars.h" #include "mozilla/gfx/gfxVars.h"
@ -1163,7 +1162,7 @@ void nsFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
MaybeScheduleReflowSVGNonDisplayText(this); MaybeScheduleReflowSVGNonDisplayText(this);
Document* doc = PresContext()->Document(); Document* doc = PresContext()->Document();
ImageLoader* loader = doc->StyleImageLoader(); ImageLoader* imageLoader = doc->StyleImageLoader();
// Continuing text frame doesn't initialize its continuation pointer before // Continuing text frame doesn't initialize its continuation pointer before
// reaching here for the first time, so we have to exclude text frames. This // reaching here for the first time, so we have to exclude text frames. This
// doesn't affect correctness because text can't match selectors. // doesn't affect correctness because text can't match selectors.
@ -1183,12 +1182,12 @@ void nsFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
aOldComputedStyle ? &aOldComputedStyle->StyleBackground()->mImage aOldComputedStyle ? &aOldComputedStyle->StyleBackground()->mImage
: nullptr; : nullptr;
const nsStyleImageLayers* newLayers = &StyleBackground()->mImage; const nsStyleImageLayers* newLayers = &StyleBackground()->mImage;
AddAndRemoveImageAssociations(*loader, this, oldLayers, newLayers); AddAndRemoveImageAssociations(*imageLoader, this, oldLayers, newLayers);
oldLayers = oldLayers =
aOldComputedStyle ? &aOldComputedStyle->StyleSVGReset()->mMask : nullptr; aOldComputedStyle ? &aOldComputedStyle->StyleSVGReset()->mMask : nullptr;
newLayers = &StyleSVGReset()->mMask; newLayers = &StyleSVGReset()->mMask;
AddAndRemoveImageAssociations(*loader, this, oldLayers, newLayers); AddAndRemoveImageAssociations(*imageLoader, this, oldLayers, newLayers);
const nsStyleDisplay* disp = StyleDisplay(); const nsStyleDisplay* disp = StyleDisplay();
bool handleStickyChange = false; bool handleStickyChange = false;
@ -1315,10 +1314,10 @@ void nsFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
if (oldBorderImage != newBorderImage) { if (oldBorderImage != newBorderImage) {
// stop and restart the image loading/notification // stop and restart the image loading/notification
if (oldBorderImage && HasImageRequest()) { if (oldBorderImage && HasImageRequest()) {
loader->DisassociateRequestFromFrame(oldBorderImage, this); imageLoader->DisassociateRequestFromFrame(oldBorderImage, this);
} }
if (newBorderImage) { if (newBorderImage) {
loader->AssociateRequestToFrame(newBorderImage, this, 0); imageLoader->AssociateRequestToFrame(newBorderImage, this, 0);
} }
} }
@ -1331,11 +1330,11 @@ void nsFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
if (oldShapeImage != newShapeImage) { if (oldShapeImage != newShapeImage) {
if (oldShapeImage && HasImageRequest()) { if (oldShapeImage && HasImageRequest()) {
loader->DisassociateRequestFromFrame(oldShapeImage, this); imageLoader->DisassociateRequestFromFrame(oldShapeImage, this);
} }
if (newShapeImage) { if (newShapeImage) {
loader->AssociateRequestToFrame(newShapeImage, this, imageLoader->AssociateRequestToFrame(
ImageLoader::REQUEST_REQUIRES_REFLOW); newShapeImage, this, ImageLoader::REQUEST_REQUIRES_REFLOW);
} }
} }

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

@ -272,6 +272,7 @@ void nsImageFrame::DestroyFrom(nsIFrame* aDestructRoot,
imageLoader->FrameDestroyed(this); imageLoader->FrameDestroyed(this);
imageLoader->RemoveNativeObserver(mListener); imageLoader->RemoveNativeObserver(mListener);
} else if (mContentURLRequest) { } else if (mContentURLRequest) {
PresContext()->Document()->ImageTracker()->Remove(mContentURLRequest);
nsLayoutUtils::DeregisterImageRequest(PresContext(), mContentURLRequest, nsLayoutUtils::DeregisterImageRequest(PresContext(), mContentURLRequest,
&mContentURLRequestRegistered); &mContentURLRequestRegistered);
mContentURLRequest->Cancel(NS_BINDING_ABORTED); mContentURLRequest->Cancel(NS_BINDING_ABORTED);
@ -367,7 +368,7 @@ void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
auto& url = const_cast<StyleComputedUrl&>( auto& url = const_cast<StyleComputedUrl&>(
styleContent->ContentAt(contentIndex).AsUrl()); styleContent->ContentAt(contentIndex).AsUrl());
Document* doc = PresContext()->Document(); Document* doc = PresContext()->Document();
if (imgRequestProxy* proxy = url.GetImage()) { if (RefPtr<imgRequestProxy> proxy = url.LoadImage(*doc)) {
proxy->Clone(mListener, doc, getter_AddRefs(mContentURLRequest)); proxy->Clone(mListener, doc, getter_AddRefs(mContentURLRequest));
SetupForContentURLRequest(); SetupForContentURLRequest();
} }
@ -393,6 +394,9 @@ void nsImageFrame::SetupForContentURLRequest() {
return; return;
} }
// We're not using nsStyleImageRequest, so manually track the image.
PresContext()->Document()->ImageTracker()->Add(mContentURLRequest);
uint32_t status = 0; uint32_t status = 0;
nsresult rv = mContentURLRequest->GetImageStatus(&status); nsresult rv = mContentURLRequest->GetImageStatus(&status);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {

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

@ -1115,10 +1115,19 @@ void Gecko_SetGradientImageValue(nsStyleImage* aImage,
aImage->SetGradientData(UniquePtr<StyleGradient>(aGradient)); aImage->SetGradientData(UniquePtr<StyleGradient>(aGradient));
} }
static already_AddRefed<nsStyleImageRequest> CreateStyleImageRequest(
nsStyleImageRequest::Mode aModeFlags, const StyleComputedImageUrl* aUrl) {
RefPtr<nsStyleImageRequest> req = new nsStyleImageRequest(aModeFlags, *aUrl);
return req.forget();
}
void Gecko_SetLayerImageImageValue(nsStyleImage* aImage, void Gecko_SetLayerImageImageValue(nsStyleImage* aImage,
const StyleComputedImageUrl* aUrl) { const StyleComputedImageUrl* aUrl) {
MOZ_ASSERT(aImage && aUrl); MOZ_ASSERT(aImage && aUrl);
aImage->SetImageUrl(*aUrl);
RefPtr<nsStyleImageRequest> req =
CreateStyleImageRequest(nsStyleImageRequest::Mode::Track, aUrl);
aImage->SetImageRequest(req.forget());
} }
void Gecko_SetImageElement(nsStyleImage* aImage, nsAtom* aAtom) { void Gecko_SetImageElement(nsStyleImage* aImage, nsAtom* aAtom) {
@ -1141,25 +1150,50 @@ void Gecko_InitializeImageCropRect(nsStyleImage* aImage) {
nsStyleImage::CropRect{zero, zero, zero, zero})); nsStyleImage::CropRect{zero, zero, zero, zero}));
} }
void Gecko_SetCursorArrayCapacity(nsStyleUI* aUi, size_t aCapacity) { void Gecko_SetCursorArrayLength(nsStyleUI* aStyleUI, size_t aLen) {
aUi->mCursorImages.Clear(); aStyleUI->mCursorImages.Clear();
aUi->mCursorImages.SetCapacity(aCapacity); aStyleUI->mCursorImages.SetLength(aLen);
} }
void Gecko_AppendCursorImage(nsStyleUI* aUi, void Gecko_SetCursorImageValue(nsCursorImage* aCursor,
const StyleComputedImageUrl* aUrl) { const StyleComputedImageUrl* aUrl) {
aUi->mCursorImages.EmplaceBack(*aUrl); MOZ_ASSERT(aCursor && aUrl);
aCursor->mImage =
CreateStyleImageRequest(nsStyleImageRequest::Mode::Discard, aUrl);
} }
void Gecko_CopyCursorArrayFrom(nsStyleUI* aDest, const nsStyleUI* aSrc) { void Gecko_CopyCursorArrayFrom(nsStyleUI* aDest, const nsStyleUI* aSrc) {
aDest->mCursorImages = aSrc->mCursorImages; aDest->mCursorImages = aSrc->mCursorImages;
} }
const nsStyleImageRequest* Gecko_GetImageRequest(const nsStyleImage* aImage) {
MOZ_ASSERT(aImage);
return aImage->ImageRequest();
}
nsAtom* Gecko_GetImageElement(const nsStyleImage* aImage) { nsAtom* Gecko_GetImageElement(const nsStyleImage* aImage) {
MOZ_ASSERT(aImage && aImage->GetType() == eStyleImageType_Element); MOZ_ASSERT(aImage && aImage->GetType() == eStyleImageType_Element);
return const_cast<nsAtom*>(aImage->GetElementId()); return const_cast<nsAtom*>(aImage->GetElementId());
} }
void Gecko_SetListStyleImageNone(nsStyleList* aList) {
aList->mListStyleImage = nullptr;
}
void Gecko_SetListStyleImageImageValue(nsStyleList* aList,
const StyleComputedImageUrl* aUrl) {
MOZ_ASSERT(aList && aUrl);
aList->mListStyleImage =
CreateStyleImageRequest(nsStyleImageRequest::Mode(0), aUrl);
}
void Gecko_CopyListStyleImageFrom(nsStyleList* aList,
const nsStyleList* aSource) {
aList->mListStyleImage = aSource->mListStyleImage;
}
void Gecko_EnsureTArrayCapacity(void* aArray, size_t aCapacity, void Gecko_EnsureTArrayCapacity(void* aArray, size_t aCapacity,
size_t aElemSize) { size_t aElemSize) {
auto base = reinterpret_cast< auto base = reinterpret_cast<
@ -1845,6 +1879,11 @@ bool Gecko_AssertClassAttrValueIsSane(const nsAttrValue* aValue) {
return true; return true;
} }
void Gecko_LoadData_DeregisterLoad(const StyleLoadData* aData) {
MOZ_ASSERT(aData->load_id != 0);
ImageLoader::DeregisterCSSImageFromAllLoaders(*aData);
}
void Gecko_PrintfStderr(const nsCString* aStr) { void Gecko_PrintfStderr(const nsCString* aStr) {
printf_stderr("%s", aStr->get()); printf_stderr("%s", aStr->get());
} }

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

@ -349,6 +349,7 @@ void Gecko_SetImageElement(nsStyleImage* image, nsAtom* atom);
void Gecko_CopyImageValueFrom(nsStyleImage* image, const nsStyleImage* other); void Gecko_CopyImageValueFrom(nsStyleImage* image, const nsStyleImage* other);
void Gecko_InitializeImageCropRect(nsStyleImage* image); void Gecko_InitializeImageCropRect(nsStyleImage* image);
const nsStyleImageRequest* Gecko_GetImageRequest(const nsStyleImage* image);
nsAtom* Gecko_GetImageElement(const nsStyleImage* image); nsAtom* Gecko_GetImageElement(const nsStyleImage* image);
// list-style-image style. // list-style-image style.
@ -360,8 +361,11 @@ void Gecko_SetListStyleImageImageValue(
void Gecko_CopyListStyleImageFrom(nsStyleList* dest, const nsStyleList* src); void Gecko_CopyListStyleImageFrom(nsStyleList* dest, const nsStyleList* src);
// cursor style. // cursor style.
void Gecko_SetCursorArrayCapacity(nsStyleUI*, size_t); void Gecko_SetCursorArrayLength(nsStyleUI* ui, size_t len);
void Gecko_AppendCursorImage(nsStyleUI*, const mozilla::StyleComputedImageUrl*);
void Gecko_SetCursorImageValue(nsCursorImage* aCursor,
const mozilla::StyleComputedImageUrl* url);
void Gecko_CopyCursorArrayFrom(nsStyleUI* dest, const nsStyleUI* src); void Gecko_CopyCursorArrayFrom(nsStyleUI* dest, const nsStyleUI* src);
// Dirtiness tracking. // Dirtiness tracking.
@ -502,7 +506,7 @@ float Gecko_FontStretch_ToFloat(mozilla::FontStretch aStretch);
void Gecko_FontStretch_SetFloat(mozilla::FontStretch* aStretch, void Gecko_FontStretch_SetFloat(mozilla::FontStretch* aStretch,
float aFloatValue); float aFloatValue);
void Gecko_LoadData_Drop(mozilla::StyleLoadData*); void Gecko_LoadData_DeregisterLoad(const mozilla::StyleLoadData*);
float Gecko_FontSlantStyle_ToFloat(mozilla::FontSlantStyle aStyle); float Gecko_FontSlantStyle_ToFloat(mozilla::FontSlantStyle aStyle);
void Gecko_FontSlantStyle_SetNormal(mozilla::FontSlantStyle*); void Gecko_FontSlantStyle_SetNormal(mozilla::FontSlantStyle*);

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

@ -12,7 +12,6 @@
#include "mozilla/dom/Document.h" #include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h" #include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/ImageTracker.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsLayoutUtils.h" #include "nsLayoutUtils.h"
#include "nsError.h" #include "nsError.h"
@ -31,56 +30,15 @@ using namespace mozilla::dom;
namespace mozilla { namespace mozilla {
namespace css { namespace css {
// This is a singleton observer which looks in the `GlobalRequestTable` to look
// at which loaders to notify.
struct GlobalImageObserver final : public imgINotificationObserver {
NS_DECL_ISUPPORTS
NS_DECL_IMGINOTIFICATIONOBSERVER
GlobalImageObserver() = default;
private:
virtual ~GlobalImageObserver() = default;
};
NS_IMPL_ADDREF(GlobalImageObserver)
NS_IMPL_RELEASE(GlobalImageObserver)
NS_INTERFACE_MAP_BEGIN(GlobalImageObserver)
NS_INTERFACE_MAP_ENTRY(imgINotificationObserver)
NS_INTERFACE_MAP_END
// Data associated with every started load.
struct ImageTableEntry {
// Set of all ImageLoaders that have registered this URL and care for updates
// for it.
nsTHashtable<nsPtrHashKey<ImageLoader>> mImageLoaders;
};
using GlobalRequestTable =
nsClassHashtable<nsRefPtrHashKey<imgIRequest>, ImageTableEntry>;
// A table of all loads, keyed by their id mapping them to the set of
// ImageLoaders they have been registered in, and recording their "canonical"
// image request.
//
// We use the load id as the key since we can only access sImages on the
// main thread, but LoadData objects might be destroyed from other threads,
// and we don't want to leave dangling pointers around.
static GlobalRequestTable* sImages = nullptr;
static StaticRefPtr<GlobalImageObserver> sImageObserver;
/* static */ /* static */
void ImageLoader::Init() { void ImageLoader::Init() {
sImages = new GlobalRequestTable(); sImages = new nsClassHashtable<nsUint64HashKey, ImageTableEntry>();
sImageObserver = new GlobalImageObserver();
} }
/* static */ /* static */
void ImageLoader::Shutdown() { void ImageLoader::Shutdown() {
delete sImages; delete sImages;
sImages = nullptr; sImages = nullptr;
sImageObserver = nullptr;
} }
void ImageLoader::DropDocumentReference() { void ImageLoader::DropDocumentReference() {
@ -91,6 +49,21 @@ void ImageLoader::DropDocumentReference() {
// been destroyed, and it also calls ClearFrames when it is destroyed. // been destroyed, and it also calls ClearFrames when it is destroyed.
ClearFrames(GetPresContext()); ClearFrames(GetPresContext());
for (auto it = mRegisteredImages.Iter(); !it.Done(); it.Next()) {
if (imgRequestProxy* request = it.Data()) {
request->CancelAndForgetObserver(NS_BINDING_ABORTED);
}
// Need to check whether the entry exists, since the css::URLValue might
// go away before ImageLoader::DropDocumentReference is called.
uint64_t imageLoadID = it.Key();
if (auto entry = sImages->Lookup(imageLoadID)) {
entry.Data()->mImageLoaders.RemoveEntry(this);
}
}
mRegisteredImages.Clear();
mDocument = nullptr; mDocument = nullptr;
} }
@ -117,31 +90,20 @@ void ImageLoader::AssociateRequestToFrame(imgIRequest* aRequest,
nsIFrame* aFrame, FrameFlags aFlags) { nsIFrame* aFrame, FrameFlags aFlags) {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
{ nsCOMPtr<imgINotificationObserver> observer;
nsCOMPtr<imgINotificationObserver> observer; aRequest->GetNotificationObserver(getter_AddRefs(observer));
aRequest->GetNotificationObserver(getter_AddRefs(observer)); if (!observer) {
if (!observer) { // The request has already been canceled, so ignore it. This is ok because
// The request has already been canceled, so ignore it. This is ok because // we're not going to get any more notifications from a canceled request.
// we're not going to get any more notifications from a canceled request. return;
return;
}
MOZ_ASSERT(observer == sImageObserver);
} }
MOZ_ASSERT(observer == this);
const auto& frameSet = const auto& frameSet =
mRequestToFrameMap.LookupForAdd(aRequest).OrInsert([=]() { mRequestToFrameMap.LookupForAdd(aRequest).OrInsert([=]() {
mDocument->ImageTracker()->Add(aRequest); nsPresContext* presContext = GetPresContext();
if (presContext) {
if (auto entry = sImages->Lookup(aRequest)) {
DebugOnly<bool> inserted =
entry.Data()->mImageLoaders.EnsureInserted(this);
MOZ_ASSERT(inserted);
} else {
MOZ_ASSERT_UNREACHABLE(
"Shouldn't be associating images not in sImages");
}
if (nsPresContext* presContext = GetPresContext()) {
nsLayoutUtils::RegisterImageRequestIfAnimated(presContext, aRequest, nsLayoutUtils::RegisterImageRequestIfAnimated(presContext, aRequest,
nullptr); nullptr);
} }
@ -242,13 +204,100 @@ void ImageLoader::AssociateRequestToFrame(imgIRequest* aRequest,
"We should only add to one map iff we also add to the other map."); "We should only add to one map iff we also add to the other map.");
} }
imgRequestProxy* ImageLoader::RegisterCSSImage(const StyleLoadData& aData) {
MOZ_ASSERT(NS_IsMainThread());
uint64_t loadId = aData.load_id;
if (loadId == 0) {
MOZ_ASSERT_UNREACHABLE("Image should have a valid LoadID");
return nullptr;
}
if (imgRequestProxy* request = mRegisteredImages.GetWeak(loadId)) {
// This document already has a request.
return request;
}
imgRequestProxy* canonicalRequest = nullptr;
{
auto entry = sImages->Lookup(loadId);
if (entry) {
canonicalRequest = entry.Data()->mCanonicalRequest;
}
if (!canonicalRequest) {
// The image was blocked or something.
return nullptr;
}
entry.Data()->mImageLoaders.PutEntry(this);
}
RefPtr<imgRequestProxy> request;
// Ignore errors here. If cloning fails for some reason we'll put a null
// entry in the hash and we won't keep trying to clone.
mInClone = true;
canonicalRequest->SyncClone(this, mDocument, getter_AddRefs(request));
mInClone = false;
MOZ_ASSERT(!mRegisteredImages.Contains(loadId));
imgRequestProxy* requestWeak = request;
mRegisteredImages.Put(loadId, request.forget());
return requestWeak;
}
/* static */
void ImageLoader::DeregisterCSSImageFromAllLoaders(const StyleLoadData& aData) {
uint64_t loadID = aData.load_id;
if (loadID == 0) {
MOZ_ASSERT_UNREACHABLE("Image should have a valid LoadID");
return;
}
if (NS_IsMainThread()) {
DeregisterCSSImageFromAllLoaders(loadID);
} else {
NS_DispatchToMainThread(NS_NewRunnableFunction(
"css::ImageLoader::DeregisterCSSImageFromAllLoaders",
[loadID] { DeregisterCSSImageFromAllLoaders(loadID); }));
}
}
/* static */
void ImageLoader::DeregisterCSSImageFromAllLoaders(uint64_t aImageLoadID) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aImageLoadID != 0);
if (auto e = sImages->Lookup(aImageLoadID)) {
const auto& tableEntry = e.Data();
if (imgRequestProxy* request = tableEntry->mCanonicalRequest) {
request->CancelAndForgetObserver(NS_BINDING_ABORTED);
}
for (auto iter = tableEntry->mImageLoaders.Iter(); !iter.Done();
iter.Next()) {
ImageLoader* loader = iter.Get()->GetKey();
if (auto e = loader->mRegisteredImages.Lookup(aImageLoadID)) {
if (imgRequestProxy* request = e.Data()) {
request->CancelAndForgetObserver(NS_BINDING_ABORTED);
}
e.Remove();
}
}
e.Remove();
}
}
void ImageLoader::RemoveRequestToFrameMapping(imgIRequest* aRequest, void ImageLoader::RemoveRequestToFrameMapping(imgIRequest* aRequest,
nsIFrame* aFrame) { nsIFrame* aFrame) {
#ifdef DEBUG #ifdef DEBUG
{ {
nsCOMPtr<imgINotificationObserver> observer; nsCOMPtr<imgINotificationObserver> observer;
aRequest->GetNotificationObserver(getter_AddRefs(observer)); aRequest->GetNotificationObserver(getter_AddRefs(observer));
MOZ_ASSERT(!observer || observer == sImageObserver); MOZ_ASSERT(!observer || observer == this);
} }
#endif #endif
@ -271,25 +320,15 @@ void ImageLoader::RemoveRequestToFrameMapping(imgIRequest* aRequest,
} }
if (frameSet->IsEmpty()) { if (frameSet->IsEmpty()) {
DeregisterImageRequest(aRequest, GetPresContext()); nsPresContext* presContext = GetPresContext();
if (presContext) {
nsLayoutUtils::DeregisterImageRequest(presContext, aRequest, nullptr);
}
entry.Remove(); entry.Remove();
} }
} }
} }
void ImageLoader::DeregisterImageRequest(imgIRequest* aRequest,
nsPresContext* aPresContext) {
mDocument->ImageTracker()->Remove(aRequest);
if (auto entry = sImages->Lookup(aRequest)) {
entry.Data()->mImageLoaders.EnsureRemoved(this);
}
if (aPresContext) {
nsLayoutUtils::DeregisterImageRequest(aPresContext, aRequest, nullptr);
}
}
void ImageLoader::RemoveFrameToRequestMapping(imgIRequest* aRequest, void ImageLoader::RemoveFrameToRequestMapping(imgIRequest* aRequest,
nsIFrame* aFrame) { nsIFrame* aFrame) {
if (auto entry = mFrameToRequestMap.Lookup(aFrame)) { if (auto entry = mFrameToRequestMap.Lookup(aFrame)) {
@ -373,7 +412,9 @@ void ImageLoader::ClearFrames(nsPresContext* aPresContext) {
} }
#endif #endif
DeregisterImageRequest(request, aPresContext); if (aPresContext) {
nsLayoutUtils::DeregisterImageRequest(aPresContext, request, nullptr);
}
} }
mRequestToFrameMap.Clear(); mRequestToFrameMap.Clear();
@ -395,12 +436,25 @@ static CORSMode EffectiveCorsMode(nsIURI* aURI,
} }
/* static */ /* static */
already_AddRefed<imgRequestProxy> ImageLoader::LoadImage( void ImageLoader::LoadImage(const StyleComputedImageUrl& aImage,
const StyleComputedImageUrl& aImage, Document& aLoadingDoc) { Document& aLoadingDoc) {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
uint64_t loadId = aImage.LoadData().load_id;
if (loadId == 0) {
MOZ_ASSERT_UNREACHABLE("Image should have a valid LoadID");
return;
}
auto lookup = sImages->LookupForAdd(loadId);
if (lookup) {
// This url has already been loaded.
return;
}
const auto& entry = lookup.OrInsert([]() { return new ImageTableEntry(); });
nsIURI* uri = aImage.GetURI(); nsIURI* uri = aImage.GetURI();
if (!uri) { if (!uri) {
return nullptr; return;
} }
int32_t loadFlags = int32_t loadFlags =
@ -412,27 +466,13 @@ already_AddRefed<imgRequestProxy> ImageLoader::LoadImage(
RefPtr<imgRequestProxy> request; RefPtr<imgRequestProxy> request;
nsresult rv = nsContentUtils::LoadImage( nsresult rv = nsContentUtils::LoadImage(
uri, &aLoadingDoc, &aLoadingDoc, data.Principal(), 0, data.ReferrerInfo(), uri, &aLoadingDoc, &aLoadingDoc, data.Principal(), 0, data.ReferrerInfo(),
sImageObserver, loadFlags, NS_LITERAL_STRING("css"), nullptr, loadFlags, NS_LITERAL_STRING("css"), getter_AddRefs(request));
getter_AddRefs(request));
if (NS_FAILED(rv) || !request) { if (NS_FAILED(rv) || !request) {
return nullptr; return;
} }
sImages->LookupForAdd(request).OrInsert([] { return new ImageTableEntry(); }); entry->mCanonicalRequest = std::move(request);
return request.forget();
}
void ImageLoader::DeregisterImageFromAllLoaders(imgRequestProxy* aImage) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aImage);
aImage->CancelAndForgetObserver(NS_BINDING_ABORTED);
if (auto lookup = sImages->Lookup(aImage)) {
MOZ_DIAGNOSTIC_ASSERT(lookup.Data()->mImageLoaders.IsEmpty(),
"Shouldn't be keeping references to any loader "
"by now");
lookup.Remove();
}
} }
nsPresContext* ImageLoader::GetPresContext() { nsPresContext* ImageLoader::GetPresContext() {
@ -571,8 +611,6 @@ void ImageLoader::RequestReflowOnFrame(FrameWithFlags* aFwf,
nsIFrame* frame = aFwf->mFrame; nsIFrame* frame = aFwf->mFrame;
// Actually request the reflow. // Actually request the reflow.
//
// FIXME(emilio): Why requesting reflow on the _parent_?
nsIFrame* parent = frame->GetInFlowParent(); nsIFrame* parent = frame->GetInFlowParent();
parent->PresShell()->FrameNeedsReflow(parent, IntrinsicDirty::StyleChange, parent->PresShell()->FrameNeedsReflow(parent, IntrinsicDirty::StyleChange,
NS_FRAME_IS_DIRTY); NS_FRAME_IS_DIRTY);
@ -580,32 +618,21 @@ void ImageLoader::RequestReflowOnFrame(FrameWithFlags* aFwf,
// We'll respond to the reflow events by unblocking onload, regardless // We'll respond to the reflow events by unblocking onload, regardless
// of whether the reflow was completed or cancelled. The callback will // of whether the reflow was completed or cancelled. The callback will
// also delete itself when it is called. // also delete itself when it is called.
auto* unblocker = new ImageReflowCallback(this, frame, aRequest); ImageReflowCallback* unblocker =
new ImageReflowCallback(this, frame, aRequest);
parent->PresShell()->PostReflowCallback(unblocker); parent->PresShell()->PostReflowCallback(unblocker);
} }
NS_IMPL_ADDREF(ImageLoader)
NS_IMPL_RELEASE(ImageLoader)
NS_INTERFACE_MAP_BEGIN(ImageLoader)
NS_INTERFACE_MAP_ENTRY(imgINotificationObserver)
NS_INTERFACE_MAP_END
NS_IMETHODIMP NS_IMETHODIMP
GlobalImageObserver::Notify(imgIRequest* aRequest, int32_t aType, ImageLoader::Notify(imgIRequest* aRequest, int32_t aType,
const nsIntRect* aData) { const nsIntRect* aData) {
auto entry = sImages->Lookup(aRequest);
MOZ_DIAGNOSTIC_ASSERT(entry);
if (MOZ_UNLIKELY(!entry)) {
return NS_OK;
}
auto& loaders = entry.Data()->mImageLoaders;
nsTArray<RefPtr<ImageLoader>> loadersToNotify(loaders.Count());
for (auto iter = loaders.Iter(); !iter.Done(); iter.Next()) {
loadersToNotify.AppendElement(iter.Get()->GetKey());
}
for (auto& loader : loadersToNotify) {
loader->Notify(aRequest, aType, aData);
}
return NS_OK;
}
nsresult ImageLoader::Notify(imgIRequest* aRequest, int32_t aType,
const nsIntRect* aData) {
#ifdef MOZ_GECKO_PROFILER #ifdef MOZ_GECKO_PROFILER
nsCString uriString; nsCString uriString;
if (profiler_is_active()) { if (profiler_is_active()) {
@ -697,7 +724,7 @@ nsresult ImageLoader::OnImageIsAnimated(imgIRequest* aRequest) {
} }
nsresult ImageLoader::OnFrameComplete(imgIRequest* aRequest) { nsresult ImageLoader::OnFrameComplete(imgIRequest* aRequest) {
if (!mDocument) { if (!mDocument || mInClone) {
return NS_OK; return NS_OK;
} }
@ -718,7 +745,7 @@ nsresult ImageLoader::OnFrameComplete(imgIRequest* aRequest) {
} }
nsresult ImageLoader::OnFrameUpdate(imgIRequest* aRequest) { nsresult ImageLoader::OnFrameUpdate(imgIRequest* aRequest) {
if (!mDocument) { if (!mDocument || mInClone) {
return NS_OK; return NS_OK;
} }
@ -733,7 +760,7 @@ nsresult ImageLoader::OnFrameUpdate(imgIRequest* aRequest) {
} }
nsresult ImageLoader::OnLoadComplete(imgIRequest* aRequest) { nsresult ImageLoader::OnLoadComplete(imgIRequest* aRequest) {
if (!mDocument) { if (!mDocument || mInClone) {
return NS_OK; return NS_OK;
} }
@ -761,6 +788,30 @@ nsresult ImageLoader::OnLoadComplete(imgIRequest* aRequest) {
return NS_OK; return NS_OK;
} }
void ImageLoader::MediaFeatureValuesChangedAllDocuments(
const MediaFeatureChange& aChange) {
// Inform every CSS image used in the document that media feature values have
// changed. If the same image is used in multiple places, then we can end up
// informing them multiple times. Theme changes are rare though and we don't
// bother trying to ensure we only do this once per image.
//
// Pull the images out into an array and iterate over them, in case the
// image notifications do something that ends up modifying the table.
nsTArray<nsCOMPtr<imgIContainer>> images;
for (auto iter = mRegisteredImages.Iter(); !iter.Done(); iter.Next()) {
imgRequestProxy* req = iter.Data();
nsCOMPtr<imgIContainer> image;
req->GetImage(getter_AddRefs(image));
if (!image) {
continue;
}
images.AppendElement(image->Unwrap());
}
for (imgIContainer* image : images) {
image->MediaFeatureValuesChangedAllDocuments(aChange);
}
}
bool ImageLoader::ImageReflowCallback::ReflowFinished() { bool ImageLoader::ImageReflowCallback::ReflowFinished() {
// Check that the frame is still valid. If it isn't, then onload was // Check that the frame is still valid. If it isn't, then onload was
// unblocked when the frame was removed from the FrameSet in // unblocked when the frame was removed from the FrameSet in
@ -788,5 +839,8 @@ void ImageLoader::ImageReflowCallback::ReflowCallbackCanceled() {
delete this; delete this;
} }
nsClassHashtable<nsUint64HashKey, ImageLoader::ImageTableEntry>*
ImageLoader::sImages = nullptr;
} // namespace css } // namespace css
} // namespace mozilla } // namespace mozilla

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

@ -19,6 +19,7 @@
#include "imgIRequest.h" #include "imgIRequest.h"
#include "imgINotificationObserver.h" #include "imgINotificationObserver.h"
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/MediaFeatureChange.h"
class imgIContainer; class imgIContainer;
class nsIFrame; class nsIFrame;
@ -37,7 +38,7 @@ namespace css {
* NOTE: All methods must be called from the main thread unless otherwise * NOTE: All methods must be called from the main thread unless otherwise
* specified. * specified.
*/ */
class ImageLoader final { class ImageLoader final : public imgINotificationObserver {
public: public:
static void Init(); static void Init();
static void Shutdown(); static void Shutdown();
@ -51,14 +52,17 @@ class ImageLoader final {
}; };
explicit ImageLoader(dom::Document* aDocument) explicit ImageLoader(dom::Document* aDocument)
: mDocument(aDocument) { : mDocument(aDocument), mInClone(false) {
MOZ_ASSERT(mDocument); MOZ_ASSERT(mDocument);
} }
NS_INLINE_DECL_REFCOUNTING(ImageLoader) NS_DECL_ISUPPORTS
NS_DECL_IMGINOTIFICATIONOBSERVER
void DropDocumentReference(); void DropDocumentReference();
imgRequestProxy* RegisterCSSImage(const StyleLoadData& aImage);
void AssociateRequestToFrame(imgIRequest* aRequest, nsIFrame* aFrame, void AssociateRequestToFrame(imgIRequest* aRequest, nsIFrame* aFrame,
FrameFlags aFlags); FrameFlags aFlags);
@ -68,24 +72,26 @@ class ImageLoader final {
void SetAnimationMode(uint16_t aMode); void SetAnimationMode(uint16_t aMode);
/**
* Called by the document's pres context when media features in all
* SVG images must be re-evaluated.
*/
void MediaFeatureValuesChangedAllDocuments(const MediaFeatureChange& aChange);
// The prescontext for this ImageLoader's document. We need it to be passed // The prescontext for this ImageLoader's document. We need it to be passed
// in because this can be called during presentation destruction after the // in because this can be called during presentation destruction after the
// presshell pointer on the document has been cleared. // presshell pointer on the document has been cleared.
void ClearFrames(nsPresContext* aPresContext); void ClearFrames(nsPresContext* aPresContext);
static already_AddRefed<imgRequestProxy> LoadImage( static void LoadImage(const StyleComputedImageUrl& aImage, dom::Document&);
const StyleComputedImageUrl&, dom::Document&);
static void DeregisterImageFromAllLoaders(imgRequestProxy*); // Cancels the image load for the given LoadData and deregisters it from any
// ImageLoaders it was registered with.
// This is called whenever an image we care about notifies the //
// GlobalImageObserver. // May be called from any thread.
nsresult Notify(imgIRequest*, int32_t aType, const nsIntRect* aData); static void DeregisterCSSImageFromAllLoaders(const StyleLoadData&);
private: private:
// Called when we stop caring about a given request.
void DeregisterImageRequest(imgIRequest*, nsPresContext*);
// This callback is used to unblock document onload after a reflow // This callback is used to unblock document onload after a reflow
// triggered from an image load. // triggered from an image load.
struct ImageReflowCallback final : public nsIReflowCallback { struct ImageReflowCallback final : public nsIReflowCallback {
@ -155,6 +161,9 @@ class ImageLoader final {
void RemoveRequestToFrameMapping(imgIRequest* aRequest, nsIFrame* aFrame); void RemoveRequestToFrameMapping(imgIRequest* aRequest, nsIFrame* aFrame);
void RemoveFrameToRequestMapping(imgIRequest* aRequest, nsIFrame* aFrame); void RemoveFrameToRequestMapping(imgIRequest* aRequest, nsIFrame* aFrame);
// Helper for the public DeregisterCSSImageFromAllLoaders overload above.
static void DeregisterCSSImageFromAllLoaders(uint64_t aLoadID);
// A map of imgIRequests to the nsIFrames that are using them. // A map of imgIRequests to the nsIFrames that are using them.
RequestToFrameMap mRequestToFrameMap; RequestToFrameMap mRequestToFrameMap;
@ -163,6 +172,40 @@ class ImageLoader final {
// A weak pointer to our document. Nulled out by DropDocumentReference. // A weak pointer to our document. Nulled out by DropDocumentReference.
dom::Document* mDocument; dom::Document* mDocument;
// A map of css ComputedUrls, keyed by their LoadID(), to the imgRequestProxy
// representing the load of the image for this ImageLoader's document.
//
// We use the LoadID() as the key since we can only access mRegisteredImages
// on the main thread, but Urls might be destroyed from other threads, and we
// don't want to leave dangling pointers around.
nsRefPtrHashtable<nsUint64HashKey, imgRequestProxy> mRegisteredImages;
// Are we cloning? If so, ignore any notifications we get.
bool mInClone;
// Data associated with every started load.
struct ImageTableEntry {
// Set of all ImageLoaders that have registered this URL.
nsTHashtable<nsPtrHashKey<ImageLoader>> mImageLoaders;
// The "canonical" image request for this URL.
//
// This request is held on to as long as the specified URL is, so that any
// image that has already started loading (or has completed loading) will
// stay alive even if all computed values referencing the image requesst
// have gone away.
RefPtr<imgRequestProxy> mCanonicalRequest;
};
// A table of all loads, keyed by their id mapping them to the set of
// ImageLoaders they have been registered in, and recording their "canonical"
// image request.
//
// We use the load id as the key since we can only access sImages on the
// main thread, but LoadData objects might be destroyed from other threads,
// and we don't want to leave dangling pointers around.
static nsClassHashtable<nsUint64HashKey, ImageTableEntry>* sImages;
}; };
} // namespace css } // namespace css

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

@ -115,8 +115,6 @@ enum class CallerType : uint32_t;
class Element; class Element;
class Document; class Document;
class ImageTracker;
} // namespace dom } // namespace dom
namespace ipc { namespace ipc {
@ -177,7 +175,6 @@ struct StyleBox {
// Work-around weird cbindgen renaming / avoiding moving stuff outside its // Work-around weird cbindgen renaming / avoiding moving stuff outside its
// namespace. // namespace.
using StyleImageTracker = dom::ImageTracker;
using StyleLoader = css::Loader; using StyleLoader = css::Loader;
using StyleLoaderReusableStyleSheets = css::LoaderReusableStyleSheets; using StyleLoaderReusableStyleSheets = css::LoaderReusableStyleSheets;
using StyleCallerType = dom::CallerType; using StyleCallerType = dom::CallerType;

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

@ -390,14 +390,12 @@ inline StyleLoadData& StyleCssUrl::LoadData() const {
inline nsIURI* StyleCssUrl::GetURI() const { inline nsIURI* StyleCssUrl::GetURI() const {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
auto& loadData = LoadData(); auto& loadData = LoadData();
if (!(loadData.flags & StyleLoadDataFlags::TRIED_TO_RESOLVE_URI)) { if (!loadData.tried_to_resolve) {
loadData.flags |= StyleLoadDataFlags::TRIED_TO_RESOLVE_URI; loadData.tried_to_resolve = true;
RefPtr<nsIURI> resolved; NS_NewURI(getter_AddRefs(loadData.resolved), SpecifiedSerialization(),
NS_NewURI(getter_AddRefs(resolved), SpecifiedSerialization(), nullptr, nullptr, ExtraData().BaseURI());
ExtraData().BaseURI());
loadData.resolved_uri = resolved.forget().take();
} }
return loadData.resolved_uri; return loadData.resolved.get();
} }
inline nsDependentCSubstring StyleComputedUrl::SpecifiedSerialization() const { inline nsDependentCSubstring StyleComputedUrl::SpecifiedSerialization() const {
@ -429,15 +427,6 @@ inline bool StyleComputedUrl::HasRef() const {
return false; return false;
} }
inline bool StyleComputedImageUrl::IsImageResolved() const {
return bool(LoadData().flags & StyleLoadDataFlags::TRIED_TO_RESOLVE_IMAGE);
}
inline imgRequestProxy* StyleComputedImageUrl::GetImage() const {
MOZ_ASSERT(IsImageResolved());
return LoadData().resolved_image;
}
template <> template <>
bool StyleGradient::IsOpaque() const; bool StyleGradient::IsOpaque() const;

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

@ -625,6 +625,11 @@ static void AddImageURL(const StyleComputedUrl& aURL,
} }
} }
static void AddImageURL(const nsStyleImageRequest& aRequest,
nsTArray<nsCString>& aURLs) {
AddImageURL(aRequest.GetImageValue(), aURLs);
}
static void AddImageURL(const nsStyleImage& aImage, static void AddImageURL(const nsStyleImage& aImage,
nsTArray<nsCString>& aURLs) { nsTArray<nsCString>& aURLs) {
if (auto* urlValue = aImage.GetURLValue()) { if (auto* urlValue = aImage.GetURLValue()) {
@ -664,7 +669,7 @@ static void CollectImageURLsForProperty(nsCSSPropertyID aProp,
switch (aProp) { switch (aProp) {
case eCSSProperty_cursor: case eCSSProperty_cursor:
for (auto& image : aStyle.StyleUI()->mCursorImages) { for (auto& image : aStyle.StyleUI()->mCursorImages) {
AddImageURL(image.mImage, aURLs); AddImageURL(*image.mImage, aURLs);
} }
break; break;
case eCSSProperty_background_image: case eCSSProperty_background_image:
@ -673,13 +678,11 @@ static void CollectImageURLsForProperty(nsCSSPropertyID aProp,
case eCSSProperty_mask_clip: case eCSSProperty_mask_clip:
AddImageURLs(aStyle.StyleSVGReset()->mMask, aURLs); AddImageURLs(aStyle.StyleSVGReset()->mMask, aURLs);
break; break;
case eCSSProperty_list_style_image: { case eCSSProperty_list_style_image:
const auto& image = aStyle.StyleList()->mListStyleImage; if (nsStyleImageRequest* image = aStyle.StyleList()->mListStyleImage) {
if (image.IsUrl()) { AddImageURL(*image, aURLs);
AddImageURL(image.AsUrl(), aURLs);
} }
break; break;
}
case eCSSProperty_border_image_source: case eCSSProperty_border_image_source:
AddImageURL(aStyle.StyleBorder()->mBorderImageSource, aURLs); AddImageURL(aStyle.StyleBorder()->mBorderImageSource, aURLs);
break; break;

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

@ -35,7 +35,6 @@
#include "mozilla/dom/ImageTracker.h" #include "mozilla/dom/ImageTracker.h"
#include "mozilla/CORSMode.h" #include "mozilla/CORSMode.h"
#include "mozilla/ClearOnShutdown.h" #include "mozilla/ClearOnShutdown.h"
#include "mozilla/GeckoBindings.h"
#include "mozilla/PreferenceSheet.h" #include "mozilla/PreferenceSheet.h"
#include "mozilla/Likely.h" #include "mozilla/Likely.h"
#include "nsIURI.h" #include "nsIURI.h"
@ -69,6 +68,19 @@ struct AssertSizeIsLessThan {
#include "nsStyleStructList.h" #include "nsStyleStructList.h"
#undef STYLE_STRUCT #undef STYLE_STRUCT
static bool DefinitelyEqualImages(const nsStyleImageRequest* aRequest1,
const nsStyleImageRequest* aRequest2) {
if (aRequest1 == aRequest2) {
return true;
}
if (!aRequest1 || !aRequest2) {
return false;
}
return aRequest1->DefinitelyEquals(*aRequest2);
}
bool StyleCssUrlData::operator==(const StyleCssUrlData& aOther) const { bool StyleCssUrlData::operator==(const StyleCssUrlData& aOther) const {
// This very intentionally avoids comparing LoadData and such. // This very intentionally avoids comparing LoadData and such.
const auto& extra = extra_data.get(); const auto& extra = extra_data.get();
@ -83,7 +95,11 @@ bool StyleCssUrlData::operator==(const StyleCssUrlData& aOther) const {
return serialization == aOther.serialization; return serialization == aOther.serialization;
} }
StyleLoadData::~StyleLoadData() { Gecko_LoadData_Drop(this); } StyleLoadData::~StyleLoadData() {
if (load_id != 0) {
css::ImageLoader::DeregisterCSSImageFromAllLoaders(*this);
}
}
already_AddRefed<nsIURI> StyleComputedUrl::ResolveLocalRef(nsIURI* aURI) const { already_AddRefed<nsIURI> StyleComputedUrl::ResolveLocalRef(nsIURI* aURI) const {
nsCOMPtr<nsIURI> result = GetURI(); nsCOMPtr<nsIURI> result = GetURI();
@ -106,124 +122,56 @@ already_AddRefed<nsIURI> StyleComputedUrl::ResolveLocalRef(
return ResolveLocalRef(aContent->GetBaseURI()); return ResolveLocalRef(aContent->GetBaseURI());
} }
void StyleComputedUrl::ResolveImage(Document& aDocument, already_AddRefed<imgRequestProxy> StyleComputedUrl::LoadImage(
const StyleComputedUrl* aOldImage) { Document& aDocument) {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
StyleLoadData& data = LoadData();
MOZ_ASSERT(!(data.flags & StyleLoadDataFlags::TRIED_TO_RESOLVE_IMAGE));
data.flags |= StyleLoadDataFlags::TRIED_TO_RESOLVE_IMAGE;
nsIURI* docURI = aDocument.GetDocumentURI(); nsIURI* docURI = aDocument.GetDocumentURI();
if (HasRef()) { if (HasRef()) {
bool isEqualExceptRef = false; bool isEqualExceptRef = false;
nsIURI* imageURI = GetURI(); nsIURI* imageURI = GetURI();
if (!imageURI) { if (!imageURI) {
return; return nullptr;
} }
if (NS_SUCCEEDED(imageURI->EqualsExceptRef(docURI, &isEqualExceptRef)) && if (NS_SUCCEEDED(imageURI->EqualsExceptRef(docURI, &isEqualExceptRef)) &&
isEqualExceptRef) { isEqualExceptRef) {
// Prevent loading an internal resource. // Prevent loading an internal resource.
return; return nullptr;
} }
} }
MOZ_ASSERT(NS_IsMainThread()); static uint64_t sNextLoadID = 1;
// TODO(emilio, bug 1440442): This is a hackaround to avoid flickering due the StyleLoadData& data = LoadData();
// lack of non-http image caching in imagelib (bug 1406134), which causes if (data.load_id == 0) {
// stuff like bug 1439285. Cleanest fix if that doesn't get fixed is bug data.load_id = sNextLoadID++;
// 1440305, but that seems too risky, and a lot of work to do before 60.
//
// Once that's fixed, the "old style" argument to TriggerImageLoads can go
// away.
const bool reuseProxy = nsContentUtils::IsChromeDoc(&aDocument) &&
aOldImage && aOldImage->IsImageResolved() &&
*this == *aOldImage;
RefPtr<imgRequestProxy> request;
if (reuseProxy) {
request = aOldImage->LoadData().resolved_image;
} else {
// NB: If aDocument is not the original document, we may not be able to load
// images from aDocument. Instead we do the image load from the original
// doc and clone it to aDocument.
Document* loadingDoc = aDocument.GetOriginalDocument();
const bool isPrint = !!loadingDoc;
if (!loadingDoc) {
loadingDoc = &aDocument;
}
// Kick off the load in the loading document.
request = css::ImageLoader::LoadImage(*this, *loadingDoc);
if (isPrint && request) {
RefPtr<imgRequestProxy> ret;
request->GetStaticRequest(&aDocument, getter_AddRefs(ret));
request = std::move(ret);
}
} }
// NB: If aDocument is not the original document, we may not be able to load
// images from aDocument. Instead we do the image load from the original doc
// and clone it to aDocument.
Document* loadingDoc = aDocument.GetOriginalDocument();
const bool isPrint = !!loadingDoc;
if (!loadingDoc) {
loadingDoc = &aDocument;
}
// Kick off the load in the loading document.
css::ImageLoader::LoadImage(*this, *loadingDoc);
// Register the image in the document that's using it.
imgRequestProxy* request =
aDocument.StyleImageLoader()->RegisterCSSImage(data);
if (!request) { if (!request) {
return; return nullptr;
} }
if (!isPrint) {
data.resolved_image = request.forget().take(); return do_AddRef(request);
// Boost priority now that we know the image is present in the ComputedStyle
// of some frame.
data.resolved_image->BoostPriority(imgIRequest::CATEGORY_FRAME_STYLE);
}
/**
* Runnable to release the image request's mRequestProxy
* and mImageTracker on the main thread, and to perform
* any necessary unlocking and untracking of the image.
*/
class StyleImageRequestCleanupTask final : public mozilla::Runnable {
public:
explicit StyleImageRequestCleanupTask(StyleLoadData& aData)
: mozilla::Runnable("StyleImageRequestCleanupTask"),
mRequestProxy(dont_AddRef(aData.resolved_image)) {
MOZ_ASSERT(mRequestProxy);
aData.resolved_image = nullptr;
} }
RefPtr<imgRequestProxy> ret;
NS_IMETHOD Run() final { request->GetStaticRequest(&aDocument, getter_AddRefs(ret));
MOZ_ASSERT(NS_IsMainThread()); return ret.forget();
css::ImageLoader::DeregisterImageFromAllLoaders(mRequestProxy);
return NS_OK;
}
protected:
virtual ~StyleImageRequestCleanupTask() {
MOZ_ASSERT(!mRequestProxy || NS_IsMainThread(),
"mRequestProxy destructor need to run on the main thread!");
}
private:
// Since we always dispatch this runnable to the main thread, these will be
// released on the main thread when the runnable itself is released.
RefPtr<imgRequestProxy> mRequestProxy;
};
// This is defined here for parallelism with LoadURI.
void Gecko_LoadData_Drop(StyleLoadData* aData) {
if (aData->resolved_image) {
auto task = MakeRefPtr<StyleImageRequestCleanupTask>(*aData);
if (NS_IsMainThread()) {
task->Run();
} else {
// if Resolve was not called at some point, mDocGroup is not set.
SystemGroup::Dispatch(TaskCategory::Other, task.forget());
}
}
// URIs are safe to refcount from any thread.
NS_IF_RELEASE(aData->resolved_uri);
} }
// -------------------- // --------------------
@ -614,7 +562,6 @@ nsChangeHint nsStyleOutline::CalcDifference(
nsStyleList::nsStyleList(const Document& aDocument) nsStyleList::nsStyleList(const Document& aDocument)
: mListStylePosition(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE), : mListStylePosition(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE),
mQuotes(StyleQuotes::Auto()), mQuotes(StyleQuotes::Auto()),
mListStyleImage(StyleImageUrlOrNone::None()),
mImageRegion(StyleClipRectOrAuto::Auto()), mImageRegion(StyleClipRectOrAuto::Auto()),
mMozListReversed(StyleMozListReversed::False) { mMozListReversed(StyleMozListReversed::False) {
MOZ_COUNT_CTOR(nsStyleList); MOZ_COUNT_CTOR(nsStyleList);
@ -627,9 +574,9 @@ nsStyleList::~nsStyleList() { MOZ_COUNT_DTOR(nsStyleList); }
nsStyleList::nsStyleList(const nsStyleList& aSource) nsStyleList::nsStyleList(const nsStyleList& aSource)
: mListStylePosition(aSource.mListStylePosition), : mListStylePosition(aSource.mListStylePosition),
mListStyleImage(aSource.mListStyleImage),
mCounterStyle(aSource.mCounterStyle), mCounterStyle(aSource.mCounterStyle),
mQuotes(aSource.mQuotes), mQuotes(aSource.mQuotes),
mListStyleImage(aSource.mListStyleImage),
mImageRegion(aSource.mImageRegion), mImageRegion(aSource.mImageRegion),
mMozListReversed(aSource.mMozListReversed) { mMozListReversed(aSource.mMozListReversed) {
MOZ_COUNT_CTOR(nsStyleList); MOZ_COUNT_CTOR(nsStyleList);
@ -639,12 +586,9 @@ void nsStyleList::TriggerImageLoads(Document& aDocument,
const nsStyleList* aOldStyle) { const nsStyleList* aOldStyle) {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (mListStyleImage.IsUrl() && !mListStyleImage.AsUrl().IsImageResolved()) { if (mListStyleImage && !mListStyleImage->IsResolved()) {
auto* oldUrl = aOldStyle && aOldStyle->mListStyleImage.IsUrl() mListStyleImage->Resolve(
? &aOldStyle->mListStyleImage.AsUrl() aDocument, aOldStyle ? aOldStyle->mListStyleImage.get() : nullptr);
: nullptr;
const_cast<StyleComputedImageUrl&>(mListStyleImage.AsUrl())
.ResolveImage(aDocument, oldUrl);
} }
} }
@ -680,7 +624,7 @@ nsChangeHint nsStyleList::CalcDifference(
} }
// list-style-image and -moz-image-region may affect some XUL elements // list-style-image and -moz-image-region may affect some XUL elements
// regardless of display value, so we still need to check them. // regardless of display value, so we still need to check them.
if (mListStyleImage != aNewData.mListStyleImage) { if (!DefinitelyEqualImages(mListStyleImage, aNewData.mListStyleImage)) {
return NS_STYLE_HINT_REFLOW; return NS_STYLE_HINT_REFLOW;
} }
if (mImageRegion != aNewData.mImageRegion) { if (mImageRegion != aNewData.mImageRegion) {
@ -695,11 +639,11 @@ nsChangeHint nsStyleList::CalcDifference(
} }
already_AddRefed<nsIURI> nsStyleList::GetListStyleImageURI() const { already_AddRefed<nsIURI> nsStyleList::GetListStyleImageURI() const {
if (!mListStyleImage.IsUrl()) { if (!mListStyleImage) {
return nullptr; return nullptr;
} }
nsCOMPtr<nsIURI> uri = mListStyleImage.AsUrl().GetURI(); nsCOMPtr<nsIURI> uri = mListStyleImage->GetImageURI();
return uri.forget(); return uri.forget();
} }
@ -1578,6 +1522,154 @@ bool StyleGradient::IsOpaque() const {
return true; return true;
} }
// --------------------
// nsStyleImageRequest
/**
* Runnable to release the nsStyleImageRequest's mRequestProxy
* and mImageTracker on the main thread, and to perform
* any necessary unlocking and untracking of the image.
*/
class StyleImageRequestCleanupTask : public mozilla::Runnable {
public:
typedef nsStyleImageRequest::Mode Mode;
StyleImageRequestCleanupTask(Mode aModeFlags,
already_AddRefed<imgRequestProxy> aRequestProxy,
already_AddRefed<ImageTracker> aImageTracker)
: mozilla::Runnable("StyleImageRequestCleanupTask"),
mModeFlags(aModeFlags),
mRequestProxy(aRequestProxy),
mImageTracker(aImageTracker) {}
NS_IMETHOD Run() final {
MOZ_ASSERT(!mRequestProxy || NS_IsMainThread(),
"If mRequestProxy is non-null, we need to run on main thread!");
if (!mRequestProxy) {
return NS_OK;
}
if (mModeFlags & Mode::Track) {
MOZ_ASSERT(mImageTracker);
mImageTracker->Remove(mRequestProxy);
} else {
mRequestProxy->UnlockImage();
}
if (mModeFlags & Mode::Discard) {
mRequestProxy->RequestDiscard();
}
return NS_OK;
}
protected:
virtual ~StyleImageRequestCleanupTask() {
MOZ_ASSERT((!mRequestProxy && !mImageTracker) || NS_IsMainThread(),
"mRequestProxy and mImageTracker's destructor need to run "
"on the main thread!");
}
private:
Mode mModeFlags;
// Since we always dispatch this runnable to the main thread, these will be
// released on the main thread when the runnable itself is released.
RefPtr<imgRequestProxy> mRequestProxy;
RefPtr<ImageTracker> mImageTracker;
};
nsStyleImageRequest::nsStyleImageRequest(Mode aModeFlags,
const StyleComputedImageUrl& aImageURL)
: mImageURL(aImageURL), mModeFlags(aModeFlags), mResolved(false) {}
nsStyleImageRequest::~nsStyleImageRequest() {
// We may or may not be being destroyed on the main thread. To clean
// up, we must untrack and unlock the image (depending on mModeFlags),
// and release mRequestProxy and mImageTracker, all on the main thread.
{
RefPtr<StyleImageRequestCleanupTask> task =
new StyleImageRequestCleanupTask(mModeFlags, mRequestProxy.forget(),
mImageTracker.forget());
if (NS_IsMainThread()) {
task->Run();
} else {
if (mDocGroup) {
mDocGroup->Dispatch(TaskCategory::Other, task.forget());
} else {
// if Resolve was not called at some point, mDocGroup is not set.
SystemGroup::Dispatch(TaskCategory::Other, task.forget());
}
}
}
MOZ_ASSERT(!mRequestProxy);
MOZ_ASSERT(!mImageTracker);
}
void nsStyleImageRequest::Resolve(Document& aDocument,
const nsStyleImageRequest* aOldImageRequest) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsResolved(), "already resolved");
mResolved = true;
// TODO(emilio, bug 1440442): This is a hackaround to avoid flickering due the
// lack of non-http image caching in imagelib (bug 1406134), which causes
// stuff like bug 1439285. Cleanest fix if that doesn't get fixed is bug
// 1440305, but that seems too risky, and a lot of work to do before 60.
//
// Once that's fixed, the "old style" argument to TriggerImageLoads can go
// away.
if (nsContentUtils::IsChromeDoc(&aDocument) && aOldImageRequest &&
aOldImageRequest->IsResolved() && DefinitelyEquals(*aOldImageRequest)) {
MOZ_ASSERT(aOldImageRequest->mDocGroup == aDocument.GetDocGroup());
MOZ_ASSERT(mModeFlags == aOldImageRequest->mModeFlags);
mDocGroup = aOldImageRequest->mDocGroup;
mImageURL = aOldImageRequest->mImageURL;
mRequestProxy = aOldImageRequest->mRequestProxy;
} else {
mDocGroup = aDocument.GetDocGroup();
mRequestProxy = mImageURL.LoadImage(aDocument);
}
if (!mRequestProxy) {
// The URL resolution or image load failed.
return;
}
// Boost priority now that we know the image is present in the ComputedStyle
// of some frame.
mRequestProxy->BoostPriority(imgIRequest::CATEGORY_FRAME_STYLE);
if (mModeFlags & Mode::Track) {
mImageTracker = aDocument.ImageTracker();
}
MaybeTrackAndLock();
}
void nsStyleImageRequest::MaybeTrackAndLock() {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(IsResolved());
MOZ_ASSERT(mRequestProxy);
if (mModeFlags & Mode::Track) {
MOZ_ASSERT(mImageTracker);
mImageTracker->Add(mRequestProxy);
} else {
MOZ_ASSERT(!mImageTracker);
mRequestProxy->LockImage();
}
}
bool nsStyleImageRequest::DefinitelyEquals(
const nsStyleImageRequest& aOther) const {
return mImageURL == aOther.mImageURL;
}
// -------------------- // --------------------
// CachedBorderImageData // CachedBorderImageData
// //
@ -1628,7 +1720,8 @@ imgIContainer* CachedBorderImageData::GetSubImage(uint8_t aIndex) {
// nsStyleImage // nsStyleImage
// //
nsStyleImage::nsStyleImage() : mCropRect(nullptr), mType(eStyleImageType_Null) { nsStyleImage::nsStyleImage()
: mType(eStyleImageType_Null), mImage(nullptr), mCropRect(nullptr) {
MOZ_COUNT_CTOR(nsStyleImage); MOZ_COUNT_CTOR(nsStyleImage);
} }
@ -1640,7 +1733,7 @@ nsStyleImage::~nsStyleImage() {
} }
nsStyleImage::nsStyleImage(const nsStyleImage& aOther) nsStyleImage::nsStyleImage(const nsStyleImage& aOther)
: mCropRect(nullptr), mType(eStyleImageType_Null) { : mType(eStyleImageType_Null), mCropRect(nullptr) {
// We need our own copy constructor because we don't want // We need our own copy constructor because we don't want
// to copy the reference count // to copy the reference count
MOZ_COUNT_CTOR(nsStyleImage); MOZ_COUNT_CTOR(nsStyleImage);
@ -1659,7 +1752,7 @@ void nsStyleImage::DoCopy(const nsStyleImage& aOther) {
SetNull(); SetNull();
if (aOther.mType == eStyleImageType_Image) { if (aOther.mType == eStyleImageType_Image) {
SetImageUrl(aOther.mImage); SetImageRequest(do_AddRef(aOther.mImage));
} else if (aOther.mType == eStyleImageType_Gradient) { } else if (aOther.mType == eStyleImageType_Gradient) {
SetGradientData(MakeUnique<StyleGradient>(*aOther.mGradient)); SetGradientData(MakeUnique<StyleGradient>(*aOther.mGradient));
} else if (aOther.mType == eStyleImageType_Element) { } else if (aOther.mType == eStyleImageType_Element) {
@ -1678,7 +1771,7 @@ void nsStyleImage::SetNull() {
delete mGradient; delete mGradient;
mGradient = nullptr; mGradient = nullptr;
} else if (mType == eStyleImageType_Image) { } else if (mType == eStyleImageType_Image) {
mImage.~StyleComputedImageUrl(); NS_RELEASE(mImage);
} else if (mType == eStyleImageType_Element) { } else if (mType == eStyleImageType_Element) {
NS_RELEASE(mElementId); NS_RELEASE(mElementId);
} }
@ -1687,14 +1780,18 @@ void nsStyleImage::SetNull() {
mCropRect = nullptr; mCropRect = nullptr;
} }
void nsStyleImage::SetImageUrl(const StyleComputedImageUrl& aImage) { void nsStyleImage::SetImageRequest(
already_AddRefed<nsStyleImageRequest> aImage) {
RefPtr<nsStyleImageRequest> image = aImage;
if (mType != eStyleImageType_Null) { if (mType != eStyleImageType_Null) {
SetNull(); SetNull();
} }
new (&mImage) StyleComputedImageUrl(aImage); if (image) {
mType = eStyleImageType_Image; mImage = image.forget().take();
mType = eStyleImageType_Image;
}
if (mCachedBIData) { if (mCachedBIData) {
mCachedBIData->PurgeCachedImages(); mCachedBIData->PurgeCachedImages();
} }
@ -1740,6 +1837,22 @@ static int32_t ConvertToPixelCoord(const StyleNumberOrPercentage& aCoord,
return NS_lround(pixelValue); return NS_lround(pixelValue);
} }
already_AddRefed<nsIURI> nsStyleImageRequest::GetImageURI() const {
nsCOMPtr<nsIURI> uri;
if (mRequestProxy) {
mRequestProxy->GetURI(getter_AddRefs(uri));
if (uri) {
return uri.forget();
}
}
// If we had some problem resolving the mRequestProxy, use the URL stored
// in the mImageURL.
uri = mImageURL.GetURI();
return uri.forget();
}
bool nsStyleImage::ComputeActualCropRect(nsIntRect& aActualCropRect, bool nsStyleImage::ComputeActualCropRect(nsIntRect& aActualCropRect,
bool* aIsEntireImage) const { bool* aIsEntireImage) const {
MOZ_ASSERT(mType == eStyleImageType_Image, MOZ_ASSERT(mType == eStyleImageType_Image,
@ -1896,7 +2009,7 @@ bool nsStyleImage::operator==(const nsStyleImage& aOther) const {
} }
if (mType == eStyleImageType_Image) { if (mType == eStyleImageType_Image) {
return mImage == aOther.mImage; return DefinitelyEqualImages(mImage, aOther.mImage);
} }
if (mType == eStyleImageType_Gradient) { if (mType == eStyleImageType_Gradient) {
@ -1933,12 +2046,12 @@ already_AddRefed<nsIURI> nsStyleImage::GetImageURI() const {
return nullptr; return nullptr;
} }
nsCOMPtr<nsIURI> uri = mImage.GetURI(); nsCOMPtr<nsIURI> uri = mImage->GetImageURI();
return uri.forget(); return uri.forget();
} }
const StyleComputedImageUrl* nsStyleImage::GetURLValue() const { const StyleComputedImageUrl* nsStyleImage::GetURLValue() const {
return mType == eStyleImageType_Image ? &mImage : nullptr; return mType == eStyleImageType_Image ? &mImage->GetImageValue() : nullptr;
} }
// -------------------- // --------------------
@ -3140,35 +3253,6 @@ nsChangeHint nsStyleContent::CalcDifference(
return nsChangeHint(0); return nsChangeHint(0);
} }
void nsStyleContent::TriggerImageLoads(Document& aDoc,
const nsStyleContent* aOld) {
if (!mContent.IsItems()) {
return;
}
Span<const StyleContentItem> oldItems;
if (aOld && aOld->mContent.IsItems()) {
oldItems = aOld->mContent.AsItems().AsSpan();
}
auto items = mContent.AsItems().AsSpan();
for (size_t i = 0; i < items.Length(); ++i) {
auto& item = items[i];
if (!item.IsUrl()) {
continue;
}
auto& url = item.AsUrl();
if (url.IsImageResolved()) {
continue;
}
auto* oldUrl = i < oldItems.Length() && oldItems[i].IsUrl()
? &oldItems[i].AsUrl()
: nullptr;
const_cast<StyleComputedImageUrl&>(url).ResolveImage(aDoc, oldUrl);
}
}
// -------------------- // --------------------
// nsStyleTextReset // nsStyleTextReset
// //
@ -3417,8 +3501,8 @@ LogicalSide nsStyleText::TextEmphasisSide(WritingMode aWM) const {
// nsStyleUI // nsStyleUI
// //
nsCursorImage::nsCursorImage(const StyleComputedImageUrl& aImage) nsCursorImage::nsCursorImage()
: mHaveHotspot(false), mHotspotX(0.0f), mHotspotY(0.0f), mImage(aImage) {} : mHaveHotspot(false), mHotspotX(0.0f), mHotspotY(0.0f) {}
nsCursorImage::nsCursorImage(const nsCursorImage& aOther) nsCursorImage::nsCursorImage(const nsCursorImage& aOther)
: mHaveHotspot(aOther.mHaveHotspot), : mHaveHotspot(aOther.mHaveHotspot),
@ -3444,7 +3528,8 @@ bool nsCursorImage::operator==(const nsCursorImage& aOther) const {
aOther.mHaveHotspot || (aOther.mHotspotX == 0 && aOther.mHotspotY == 0), aOther.mHaveHotspot || (aOther.mHotspotX == 0 && aOther.mHotspotY == 0),
"expected mHotspot{X,Y} to be 0 when mHaveHotspot is false"); "expected mHotspot{X,Y} to be 0 when mHaveHotspot is false");
return mHaveHotspot == aOther.mHaveHotspot && mHotspotX == aOther.mHotspotX && return mHaveHotspot == aOther.mHaveHotspot && mHotspotX == aOther.mHotspotX &&
mHotspotY == aOther.mHotspotY && mImage == aOther.mImage; mHotspotY == aOther.mHotspotY &&
DefinitelyEqualImages(mImage, aOther.mImage);
} }
nsStyleUI::nsStyleUI(const Document& aDocument) nsStyleUI::nsStyleUI(const Document& aDocument)
@ -3479,13 +3564,13 @@ void nsStyleUI::TriggerImageLoads(Document& aDocument,
for (size_t i = 0; i < mCursorImages.Length(); ++i) { for (size_t i = 0; i < mCursorImages.Length(); ++i) {
nsCursorImage& cursor = mCursorImages[i]; nsCursorImage& cursor = mCursorImages[i];
if (!cursor.mImage.IsImageResolved()) { if (cursor.mImage && !cursor.mImage->IsResolved()) {
const nsCursorImage* oldCursor = const nsCursorImage* oldCursor =
(aOldStyle && aOldStyle->mCursorImages.Length() > i) (aOldStyle && aOldStyle->mCursorImages.Length() > i)
? &aOldStyle->mCursorImages[i] ? &aOldStyle->mCursorImages[i]
: nullptr; : nullptr;
cursor.mImage.ResolveImage(aDocument, cursor.mImage->Resolve(aDocument,
oldCursor ? &oldCursor->mImage : nullptr); oldCursor ? oldCursor->mImage.get() : nullptr);
} }
} }
} }

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

@ -133,6 +133,96 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleFont {
RefPtr<nsAtom> mLanguage; RefPtr<nsAtom> mLanguage;
}; };
/**
* A wrapper for an imgRequestProxy that supports off-main-thread creation
* and equality comparison.
*
* An nsStyleImageRequest can be created using the constructor that takes the
* URL, base URI, referrer and principal that can be used to initiate an image
* load and produce an imgRequestProxy later.
*
* This can be called from any thread. The nsStyleImageRequest is not
* considered "resolved" at this point, and the Resolve() method must be called
* later to initiate the image load and make calls to get() valid.
*
* Calls to TrackImage(), UntrackImage(), LockImage(), UnlockImage() and
* RequestDiscard() are made to the imgRequestProxy and ImageTracker as
* appropriate, according to the mode flags passed in to the constructor.
*
* The constructor receives a css::URLValue to represent the url()
* information, which is held on to for the comparisons done in
* DefinitelyEquals().
*/
class nsStyleImageRequest {
public:
// Flags describing whether the imgRequestProxy must be tracked in the
// ImageTracker, whether LockImage/UnlockImage calls will be made
// when obtaining and releasing the imgRequestProxy, and whether
// RequestDiscard will be called on release.
enum class Mode : uint8_t {
// The imgRequestProxy will be added to the ImageTracker when resolved
// Without this flag, the nsStyleImageRequest itself will call LockImage/
// UnlockImage on the imgRequestProxy, rather than leaving locking to the
// ImageTracker to manage.
//
// This flag is currently used by all nsStyleImageRequests except
// those for list-style-image and cursor.
Track = 0x1,
// The imgRequestProxy will have its RequestDiscard method called when
// the nsStyleImageRequest is going away.
//
// This is currently used only for cursor images.
Discard = 0x2,
};
// Can be called from any thread, but Resolve() must be called later
// on the main thread before get() can be used.
nsStyleImageRequest(Mode aModeFlags, const mozilla::StyleComputedImageUrl&);
void Resolve(mozilla::dom::Document&,
const nsStyleImageRequest* aOldImageRequest);
bool IsResolved() const { return mResolved; }
imgRequestProxy* get() {
MOZ_ASSERT(IsResolved(), "Resolve() must be called first");
MOZ_ASSERT(NS_IsMainThread());
return mRequestProxy.get();
}
const imgRequestProxy* get() const {
return const_cast<nsStyleImageRequest*>(this)->get();
}
// Returns whether the URLValue objects in the two nsStyleImageRequests
// return true from URLValue::DefinitelyEqualURIs.
bool DefinitelyEquals(const nsStyleImageRequest& aOther) const;
const mozilla::StyleComputedImageUrl& GetImageValue() const {
return mImageURL;
}
already_AddRefed<nsIURI> GetImageURI() const;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsStyleImageRequest);
private:
~nsStyleImageRequest();
nsStyleImageRequest& operator=(const nsStyleImageRequest& aOther) = delete;
void MaybeTrackAndLock();
RefPtr<imgRequestProxy> mRequestProxy;
mozilla::StyleComputedImageUrl mImageURL;
RefPtr<mozilla::dom::ImageTracker> mImageTracker;
// Cache DocGroup for dispatching events in the destructor.
RefPtr<mozilla::dom::DocGroup> mDocGroup;
Mode mModeFlags;
bool mResolved;
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsStyleImageRequest::Mode)
enum nsStyleImageType { enum nsStyleImageType {
eStyleImageType_Null, eStyleImageType_Null,
eStyleImageType_Image, eStyleImageType_Image,
@ -178,34 +268,36 @@ struct nsStyleImage {
nsStyleImage& operator=(const nsStyleImage& aOther); nsStyleImage& operator=(const nsStyleImage& aOther);
void SetNull(); void SetNull();
void SetImageUrl(const mozilla::StyleComputedImageUrl&); void SetImageRequest(already_AddRefed<nsStyleImageRequest> aImage);
void SetGradientData(mozilla::UniquePtr<mozilla::StyleGradient>); void SetGradientData(mozilla::UniquePtr<mozilla::StyleGradient>);
void SetElementId(already_AddRefed<nsAtom> aElementId); void SetElementId(already_AddRefed<nsAtom> aElementId);
void SetCropRect(mozilla::UniquePtr<CropRect> aCropRect); void SetCropRect(mozilla::UniquePtr<CropRect> aCropRect);
void ResolveImage(mozilla::dom::Document& aDocument, void ResolveImage(mozilla::dom::Document& aDocument,
const nsStyleImage* aOldImage) { const nsStyleImage* aOldImage) {
if (mType == eStyleImageType_Image && !mImage.IsImageResolved()) { MOZ_ASSERT(mType != eStyleImageType_Image || mImage);
const auto* oldRequest = if (mType == eStyleImageType_Image && !mImage->IsResolved()) {
const nsStyleImageRequest* oldRequest =
(aOldImage && aOldImage->GetType() == eStyleImageType_Image) (aOldImage && aOldImage->GetType() == eStyleImageType_Image)
? &aOldImage->ImageUrl() ? aOldImage->ImageRequest()
: nullptr; : nullptr;
mImage.ResolveImage(aDocument, oldRequest); mImage->Resolve(aDocument, oldRequest);
} }
} }
nsStyleImageType GetType() const { return mType; } nsStyleImageType GetType() const { return mType; }
const mozilla::StyleComputedImageUrl& ImageUrl() const { nsStyleImageRequest* ImageRequest() const {
MOZ_ASSERT(mType == eStyleImageType_Image, "Data is not an image!"); MOZ_ASSERT(mType == eStyleImageType_Image, "Data is not an image!");
MOZ_ASSERT(mImage);
return mImage; return mImage;
} }
imgRequestProxy* GetImageData() const { return ImageUrl().GetImage(); } imgRequestProxy* GetImageData() const { return ImageRequest()->get(); }
const mozilla::StyleGradient& GetGradient() const { const mozilla::StyleGradient& GetGradient() const {
NS_ASSERTION(mType == eStyleImageType_Gradient, "Data is not a gradient!"); NS_ASSERTION(mType == eStyleImageType_Gradient, "Data is not a gradient!");
return *mGradient; return *mGradient;
} }
bool IsResolved() const { bool IsResolved() const {
return mType != eStyleImageType_Image || ImageUrl().IsImageResolved(); return mType != eStyleImageType_Image || ImageRequest()->IsResolved();
} }
const nsAtom* GetElementId() const { const nsAtom* GetElementId() const {
NS_ASSERTION(mType == eStyleImageType_Element, "Data is not an element!"); NS_ASSERTION(mType == eStyleImageType_Element, "Data is not an element!");
@ -299,15 +391,15 @@ struct nsStyleImage {
// allocated since it is only used in border image case. // allocated since it is only used in border image case.
mozilla::UniquePtr<CachedBorderImageData> mCachedBIData; mozilla::UniquePtr<CachedBorderImageData> mCachedBIData;
// This is _currently_ used only in conjunction with eStyleImageType_Image.
mozilla::UniquePtr<CropRect> mCropRect;
nsStyleImageType mType; nsStyleImageType mType;
union { union {
mozilla::StyleComputedImageUrl mImage; nsStyleImageRequest* mImage;
mozilla::StyleGradient* mGradient; mozilla::StyleGradient* mGradient;
nsAtom* mElementId; nsAtom* mElementId;
}; };
// This is _currently_ used only in conjunction with eStyleImageType_Image.
mozilla::UniquePtr<CropRect> mCropRect;
}; };
struct nsStyleImageLayers { struct nsStyleImageLayers {
@ -828,10 +920,6 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList {
nsStyleList(const nsStyleList& aStyleList); nsStyleList(const nsStyleList& aStyleList);
~nsStyleList(); ~nsStyleList();
private:
nsStyleList& operator=(const nsStyleList& aOther) = delete;
public:
void TriggerImageLoads(mozilla::dom::Document&, const nsStyleList*); void TriggerImageLoads(mozilla::dom::Document&, const nsStyleList*);
static constexpr bool kHasTriggerImageLoads = true; static constexpr bool kHasTriggerImageLoads = true;
@ -839,8 +927,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList {
const nsStyleDisplay& aOldDisplay) const; const nsStyleDisplay& aOldDisplay) const;
imgRequestProxy* GetListStyleImage() const { imgRequestProxy* GetListStyleImage() const {
return mListStyleImage.IsUrl() ? mListStyleImage.AsUrl().GetImage() return mListStyleImage ? mListStyleImage->get() : nullptr;
: nullptr;
} }
nsRect GetImageRegion() const { nsRect GetImageRegion() const {
@ -853,15 +940,18 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList {
already_AddRefed<nsIURI> GetListStyleImageURI() const; already_AddRefed<nsIURI> GetListStyleImageURI() const;
uint8_t mListStylePosition; uint8_t mListStylePosition;
RefPtr<nsStyleImageRequest> mListStyleImage;
mozilla::CounterStylePtr mCounterStyle; mozilla::CounterStylePtr mCounterStyle;
mozilla::StyleQuotes mQuotes;
mozilla::StyleImageUrlOrNone mListStyleImage;
// the rect to use within an image. private:
mozilla::StyleClipRectOrAuto mImageRegion; nsStyleList& operator=(const nsStyleList& aOther) = delete;
// true in an <ol reversed> scope.
mozilla::StyleMozListReversed mMozListReversed; public:
mozilla::StyleQuotes mQuotes;
mozilla::StyleClipRectOrAuto mImageRegion; // the rect to use within an image
mozilla::StyleMozListReversed
mMozListReversed; // true in an <ol reversed> scope
}; };
struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePosition { struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePosition {
@ -1829,9 +1919,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleContent {
explicit nsStyleContent(const mozilla::dom::Document&); explicit nsStyleContent(const mozilla::dom::Document&);
nsStyleContent(const nsStyleContent& aContent); nsStyleContent(const nsStyleContent& aContent);
~nsStyleContent(); ~nsStyleContent();
static constexpr bool kHasTriggerImageLoads = false;
void TriggerImageLoads(mozilla::dom::Document&, const nsStyleContent*);
static constexpr bool kHasTriggerImageLoads = true;
size_t ContentCount() const { size_t ContentCount() const {
return mContent.IsItems() ? mContent.AsItems().Length() : 0; return mContent.IsItems() ? mContent.AsItems().Length() : 0;
@ -1871,10 +1959,10 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUIReset {
struct nsCursorImage { struct nsCursorImage {
bool mHaveHotspot; bool mHaveHotspot;
float mHotspotX, mHotspotY; float mHotspotX, mHotspotY;
mozilla::StyleComputedImageUrl mImage; RefPtr<nsStyleImageRequest> mImage;
explicit nsCursorImage(const mozilla::StyleComputedImageUrl&); nsCursorImage();
nsCursorImage(const nsCursorImage&); nsCursorImage(const nsCursorImage& aOther);
nsCursorImage& operator=(const nsCursorImage& aOther); nsCursorImage& operator=(const nsCursorImage& aOther);
@ -1883,7 +1971,7 @@ struct nsCursorImage {
return !(*this == aOther); return !(*this == aOther);
} }
imgRequestProxy* GetImage() const { return mImage.GetImage(); } imgRequestProxy* GetImage() const { return mImage->get(); }
}; };
struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUI { struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUI {

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

@ -876,16 +876,17 @@ void SVGMaskObserverList::ResolveImage(uint32_t aIndex) {
const nsStyleSVGReset* svgReset = mFrame->StyleSVGReset(); const nsStyleSVGReset* svgReset = mFrame->StyleSVGReset();
MOZ_ASSERT(aIndex < svgReset->mMask.mImageCount); MOZ_ASSERT(aIndex < svgReset->mMask.mImageCount);
auto& image = nsStyleImage& image =
const_cast<nsStyleImage&>(svgReset->mMask.mLayers[aIndex].mImage); const_cast<nsStyleImage&>(svgReset->mMask.mLayers[aIndex].mImage);
if (!image.IsResolved()) { if (!image.IsResolved()) {
MOZ_ASSERT(image.GetType() == nsStyleImageType::eStyleImageType_Image); MOZ_ASSERT(image.GetType() == nsStyleImageType::eStyleImageType_Image);
image.ResolveImage(*mFrame->PresContext()->Document(), nullptr); image.ResolveImage(*mFrame->PresContext()->Document(), nullptr);
Document* doc = mFrame->PresContext()->Document(); mozilla::css::ImageLoader* imageLoader =
mFrame->PresContext()->Document()->StyleImageLoader();
if (imgRequestProxy* req = image.GetImageData()) { if (imgRequestProxy* req = image.GetImageData()) {
doc->StyleImageLoader()->AssociateRequestToFrame(req, mFrame, 0); imageLoader->AssociateRequestToFrame(req, mFrame, 0);
} }
} }
} }

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

@ -15,6 +15,7 @@ use crate::gecko_bindings::structs::{self, Matrix4x4Components};
use crate::gecko_bindings::structs::{nsStyleImage, nsresult}; use crate::gecko_bindings::structs::{nsStyleImage, nsresult};
use crate::stylesheets::RulesMutateError; use crate::stylesheets::RulesMutateError;
use crate::values::computed::transform::Matrix3D; use crate::values::computed::transform::Matrix3D;
use crate::values::computed::url::ComputedImageUrl;
use crate::values::computed::{Gradient, Image, TextAlign}; use crate::values::computed::{Gradient, Image, TextAlign};
use crate::values::generics::image::GenericImage; use crate::values::generics::image::GenericImage;
use crate::values::generics::rect::Rect; use crate::values::generics::rect::Rect;
@ -62,7 +63,7 @@ impl nsStyleImage {
match self.mType { match self.mType {
nsStyleImageType::eStyleImageType_Null => None, nsStyleImageType::eStyleImageType_Null => None,
nsStyleImageType::eStyleImageType_Image => { nsStyleImageType::eStyleImageType_Image => {
let url = self.__bindgen_anon_1.mImage.as_ref().clone(); let url = self.get_image_url();
if self.mCropRect.mPtr.is_null() { if self.mCropRect.mPtr.is_null() {
Some(GenericImage::Url(url)) Some(GenericImage::Url(url))
} else { } else {
@ -87,6 +88,13 @@ impl nsStyleImage {
}, },
} }
} }
unsafe fn get_image_url(&self) -> ComputedImageUrl {
let image_request = bindings::Gecko_GetImageRequest(self)
.as_ref()
.expect("Null image request?");
ComputedImageUrl::from_image_request(image_request)
}
} }
pub mod basic_shape { pub mod basic_shape {

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

@ -6,6 +6,8 @@
use crate::gecko_bindings::bindings; use crate::gecko_bindings::bindings;
use crate::gecko_bindings::structs; use crate::gecko_bindings::structs;
use crate::gecko_bindings::structs::nsStyleImageRequest;
use crate::gecko_bindings::sugar::refptr::RefPtr;
use crate::parser::{Parse, ParserContext}; use crate::parser::{Parse, ParserContext};
use crate::stylesheets::{CorsMode, UrlExtraData}; use crate::stylesheets::{CorsMode, UrlExtraData};
use crate::values::computed::{Context, ToComputedValue}; use crate::values::computed::{Context, ToComputedValue};
@ -148,52 +150,31 @@ struct LoadDataKey(*const LoadDataSource);
unsafe impl Sync for LoadDataKey {} unsafe impl Sync for LoadDataKey {}
unsafe impl Send for LoadDataKey {} unsafe impl Send for LoadDataKey {}
bitflags! { /// The load data for a given URL. This is mutable from C++, for now at least.
/// Various bits of mutable state that are kept for image loads.
#[repr(C)]
pub struct LoadDataFlags: u8 {
/// Whether we tried to resolve the uri at least once.
const TRIED_TO_RESOLVE_URI = 1 << 0;
/// Whether we tried to resolve the image at least once.
const TRIED_TO_RESOLVE_IMAGE = 1 << 1;
}
}
/// This is usable and movable from multiple threads just fine, as long as it's
/// not cloned (it is not clonable), and the methods that mutate it run only on
/// the main thread (when all the other threads we care about are paused).
unsafe impl Sync for LoadData {}
unsafe impl Send for LoadData {}
/// The load data for a given URL. This is mutable from C++, and shouldn't be
/// accessed from rust for anything.
#[repr(C)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]
pub struct LoadData { pub struct LoadData {
/// A strong reference to the imgRequestProxy, if any, that should be resolved: RefPtr<structs::nsIURI>,
/// released on drop. load_id: u64,
/// tried_to_resolve: bool,
/// These are raw pointers because they are not safe to reference-count off
/// the main thread.
resolved_image: *mut structs::imgRequestProxy,
/// A strong reference to the resolved URI of this image.
resolved_uri: *mut structs::nsIURI,
/// A few flags that are set when resolving the image or such.
flags: LoadDataFlags,
} }
impl Drop for LoadData { impl Drop for LoadData {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { bindings::Gecko_LoadData_Drop(self) } if self.load_id != 0 {
unsafe {
bindings::Gecko_LoadData_DeregisterLoad(self);
}
}
} }
} }
impl Default for LoadData { impl Default for LoadData {
fn default() -> Self { fn default() -> Self {
Self { Self {
resolved_image: std::ptr::null_mut(), resolved: RefPtr::null(),
resolved_uri: std::ptr::null_mut(), load_id: 0,
flags: LoadDataFlags::empty(), tried_to_resolve: false,
} }
} }
} }
@ -361,6 +342,13 @@ impl ToCss for ComputedUrl {
#[repr(transparent)] #[repr(transparent)]
pub struct ComputedImageUrl(pub ComputedUrl); pub struct ComputedImageUrl(pub ComputedUrl);
impl ComputedImageUrl {
/// Convert from nsStyleImageRequest to ComputedImageUrl.
pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Self {
image_request.mImageURL.clone()
}
}
impl ToCss for ComputedImageUrl { impl ToCss for ComputedImageUrl {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where where

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

@ -25,9 +25,14 @@ use crate::gecko_bindings::bindings::Gecko_CopyCounterStyle;
use crate::gecko_bindings::bindings::Gecko_CopyCursorArrayFrom; use crate::gecko_bindings::bindings::Gecko_CopyCursorArrayFrom;
use crate::gecko_bindings::bindings::Gecko_CopyFontFamilyFrom; use crate::gecko_bindings::bindings::Gecko_CopyFontFamilyFrom;
use crate::gecko_bindings::bindings::Gecko_CopyImageValueFrom; use crate::gecko_bindings::bindings::Gecko_CopyImageValueFrom;
use crate::gecko_bindings::bindings::Gecko_CopyListStyleImageFrom;
use crate::gecko_bindings::bindings::Gecko_EnsureImageLayersLength; use crate::gecko_bindings::bindings::Gecko_EnsureImageLayersLength;
use crate::gecko_bindings::bindings::Gecko_SetCursorArrayLength;
use crate::gecko_bindings::bindings::Gecko_SetCursorImageValue;
use crate::gecko_bindings::bindings::Gecko_nsStyleFont_SetLang; use crate::gecko_bindings::bindings::Gecko_nsStyleFont_SetLang;
use crate::gecko_bindings::bindings::Gecko_nsStyleFont_CopyLangFrom; use crate::gecko_bindings::bindings::Gecko_nsStyleFont_CopyLangFrom;
use crate::gecko_bindings::bindings::Gecko_SetListStyleImageNone;
use crate::gecko_bindings::bindings::Gecko_SetListStyleImageImageValue;
use crate::gecko_bindings::bindings::Gecko_SetNullImageValue; use crate::gecko_bindings::bindings::Gecko_SetNullImageValue;
use crate::gecko_bindings::structs; use crate::gecko_bindings::structs;
use crate::gecko_bindings::structs::nsCSSPropertyID; use crate::gecko_bindings::structs::nsCSSPropertyID;
@ -48,6 +53,7 @@ use crate::values::computed::BorderStyle;
use crate::values::computed::font::FontSize; use crate::values::computed::font::FontSize;
use crate::values::generics::column::ColumnCount; use crate::values::generics::column::ColumnCount;
use crate::values::generics::image::ImageLayer; use crate::values::generics::image::ImageLayer;
use crate::values::generics::url::UrlOrNone;
pub mod style_structs { pub mod style_structs {
@ -2102,7 +2108,43 @@ fn static_assert() {
<% impl_simple_image_array_property("blend_mode", "background", "mImage", "mBlendMode", "Background") %> <% impl_simple_image_array_property("blend_mode", "background", "mImage", "mBlendMode", "Background") %>
</%self:impl_trait> </%self:impl_trait>
<%self:impl_trait style_struct_name="List" skip_longhands="list-style-type"> <%self:impl_trait style_struct_name="List"
skip_longhands="list-style-image list-style-type">
pub fn set_list_style_image(&mut self, image: longhands::list_style_image::computed_value::T) {
match image {
UrlOrNone::None => {
unsafe {
Gecko_SetListStyleImageNone(&mut *self.gecko);
}
}
UrlOrNone::Url(ref url) => {
unsafe {
Gecko_SetListStyleImageImageValue(&mut *self.gecko, url);
}
}
}
}
pub fn copy_list_style_image_from(&mut self, other: &Self) {
unsafe { Gecko_CopyListStyleImageFrom(&mut *self.gecko, &*other.gecko); }
}
pub fn reset_list_style_image(&mut self, other: &Self) {
self.copy_list_style_image_from(other)
}
pub fn clone_list_style_image(&self) -> longhands::list_style_image::computed_value::T {
if self.gecko.mListStyleImage.mRawPtr.is_null() {
return UrlOrNone::None;
}
unsafe {
let ref gecko_image_request = *self.gecko.mListStyleImage.mRawPtr;
UrlOrNone::Url(ComputedImageUrl::from_image_request(gecko_image_request))
}
}
pub fn set_list_style_type(&mut self, v: longhands::list_style_type::computed_value::T) { pub fn set_list_style_type(&mut self, v: longhands::list_style_type::computed_value::T) {
use nsstring::{nsACString, nsCStr}; use nsstring::{nsACString, nsCStr};
use self::longhands::list_style_type::computed_value::T; use self::longhands::list_style_type::computed_value::T;
@ -2391,11 +2433,14 @@ clip-path
pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) { pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) {
self.gecko.mCursor = v.keyword; self.gecko.mCursor = v.keyword;
unsafe { unsafe {
bindings::Gecko_SetCursorArrayCapacity(&mut *self.gecko, v.images.len()); Gecko_SetCursorArrayLength(&mut *self.gecko, v.images.len());
} }
for i in 0..v.images.len() { for i in 0..v.images.len() {
unsafe { unsafe {
bindings::Gecko_AppendCursorImage(&mut *self.gecko, &v.images[i].url); Gecko_SetCursorImageValue(
&mut self.gecko.mCursorImages[i],
&v.images[i].url
);
} }
match v.images[i].hotspot { match v.images[i].hotspot {
@ -2428,7 +2473,10 @@ clip-path
let keyword = self.gecko.mCursor; let keyword = self.gecko.mCursor;
let images = self.gecko.mCursorImages.iter().map(|gecko_cursor_image| { let images = self.gecko.mCursorImages.iter().map(|gecko_cursor_image| {
let url = gecko_cursor_image.mImage.clone(); let url = unsafe {
let gecko_image_request = gecko_cursor_image.mImage.mRawPtr.as_ref().unwrap();
ComputedImageUrl::from_image_request(&gecko_image_request)
};
let hotspot = let hotspot =
if gecko_cursor_image.mHaveHotspot { if gecko_cursor_image.mHaveHotspot {

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

@ -170,7 +170,6 @@ include = [
"ComputedUrl", "ComputedUrl",
"ComputedImageUrl", "ComputedImageUrl",
"UrlOrNone", "UrlOrNone",
"ImageUrlOrNone",
"Filter", "Filter",
"Gradient", "Gradient",
"GridTemplateAreas", "GridTemplateAreas",
@ -207,7 +206,6 @@ renaming_overrides_prefixing = true
"nscolor" = "nscolor" "nscolor" = "nscolor"
"nsAtom" = "nsAtom" "nsAtom" = "nsAtom"
"nsIURI" = "nsIURI" "nsIURI" = "nsIURI"
"imgRequestProxy" = "imgRequestProxy"
"nsCompatibility" = "nsCompatibility" "nsCompatibility" = "nsCompatibility"
"SharedFontList" = "SharedFontList" "SharedFontList" = "SharedFontList"
"nsSimpleContentList" = "nsSimpleContentList" "nsSimpleContentList" = "nsSimpleContentList"
@ -653,11 +651,7 @@ renaming_overrides_prefixing = true
inline StyleCorsMode CorsMode() const; inline StyleCorsMode CorsMode() const;
already_AddRefed<nsIURI> ResolveLocalRef(nsIURI* aBase) const; already_AddRefed<nsIURI> ResolveLocalRef(nsIURI* aBase) const;
already_AddRefed<nsIURI> ResolveLocalRef(const nsIContent* aContent) const; already_AddRefed<nsIURI> ResolveLocalRef(const nsIContent* aContent) const;
already_AddRefed<imgRequestProxy> LoadImage(mozilla::dom::Document&);
// Only relevant for images.
inline bool IsImageResolved() const;
inline imgRequestProxy* GetImage() const;
void ResolveImage(dom::Document&, const StyleComputedUrl* aOldImage);
""" """
"GenericGradient" = """ "GenericGradient" = """