зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset c9f4dd3ed78b (bug 1606628) for causing failures in ImageLoader.cpp
CLOSED TREE
This commit is contained in:
Родитель
77c6b3e983
Коммит
823e8c21f1
|
@ -56,6 +56,7 @@ class ImageTracker {
|
|||
void SetAnimatingState(bool aAnimating);
|
||||
|
||||
void RequestDiscardAll();
|
||||
|
||||
void MediaFeatureValuesChangedAllDocuments(const MediaFeatureChange&);
|
||||
|
||||
private:
|
||||
|
|
|
@ -1525,6 +1525,7 @@ void nsPresContext::MediaFeatureValuesChangedAllDocuments(
|
|||
|
||||
// Propagate the media feature value change down to any SVG images the
|
||||
// document is using.
|
||||
mDocument->StyleImageLoader()->MediaFeatureValuesChangedAllDocuments(aChange);
|
||||
mDocument->ImageTracker()->MediaFeatureValuesChangedAllDocuments(aChange);
|
||||
|
||||
// And then into any subdocuments.
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "mozilla/ComputedStyle.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/dom/ElementInlines.h"
|
||||
#include "mozilla/dom/ImageTracker.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
|
@ -1163,7 +1162,7 @@ void nsFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
|
|||
MaybeScheduleReflowSVGNonDisplayText(this);
|
||||
|
||||
Document* doc = PresContext()->Document();
|
||||
ImageLoader* loader = doc->StyleImageLoader();
|
||||
ImageLoader* imageLoader = doc->StyleImageLoader();
|
||||
// Continuing text frame doesn't initialize its continuation pointer before
|
||||
// reaching here for the first time, so we have to exclude text frames. This
|
||||
// doesn't affect correctness because text can't match selectors.
|
||||
|
@ -1183,12 +1182,12 @@ void nsFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
|
|||
aOldComputedStyle ? &aOldComputedStyle->StyleBackground()->mImage
|
||||
: nullptr;
|
||||
const nsStyleImageLayers* newLayers = &StyleBackground()->mImage;
|
||||
AddAndRemoveImageAssociations(*loader, this, oldLayers, newLayers);
|
||||
AddAndRemoveImageAssociations(*imageLoader, this, oldLayers, newLayers);
|
||||
|
||||
oldLayers =
|
||||
aOldComputedStyle ? &aOldComputedStyle->StyleSVGReset()->mMask : nullptr;
|
||||
newLayers = &StyleSVGReset()->mMask;
|
||||
AddAndRemoveImageAssociations(*loader, this, oldLayers, newLayers);
|
||||
AddAndRemoveImageAssociations(*imageLoader, this, oldLayers, newLayers);
|
||||
|
||||
const nsStyleDisplay* disp = StyleDisplay();
|
||||
bool handleStickyChange = false;
|
||||
|
@ -1315,10 +1314,10 @@ void nsFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
|
|||
if (oldBorderImage != newBorderImage) {
|
||||
// stop and restart the image loading/notification
|
||||
if (oldBorderImage && HasImageRequest()) {
|
||||
loader->DisassociateRequestFromFrame(oldBorderImage, this);
|
||||
imageLoader->DisassociateRequestFromFrame(oldBorderImage, this);
|
||||
}
|
||||
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 && HasImageRequest()) {
|
||||
loader->DisassociateRequestFromFrame(oldShapeImage, this);
|
||||
imageLoader->DisassociateRequestFromFrame(oldShapeImage, this);
|
||||
}
|
||||
if (newShapeImage) {
|
||||
loader->AssociateRequestToFrame(newShapeImage, this,
|
||||
ImageLoader::REQUEST_REQUIRES_REFLOW);
|
||||
imageLoader->AssociateRequestToFrame(
|
||||
newShapeImage, this, ImageLoader::REQUEST_REQUIRES_REFLOW);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -272,6 +272,7 @@ void nsImageFrame::DestroyFrom(nsIFrame* aDestructRoot,
|
|||
imageLoader->FrameDestroyed(this);
|
||||
imageLoader->RemoveNativeObserver(mListener);
|
||||
} else if (mContentURLRequest) {
|
||||
PresContext()->Document()->ImageTracker()->Remove(mContentURLRequest);
|
||||
nsLayoutUtils::DeregisterImageRequest(PresContext(), mContentURLRequest,
|
||||
&mContentURLRequestRegistered);
|
||||
mContentURLRequest->Cancel(NS_BINDING_ABORTED);
|
||||
|
@ -367,7 +368,7 @@ void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
|
|||
auto& url = const_cast<StyleComputedUrl&>(
|
||||
styleContent->ContentAt(contentIndex).AsUrl());
|
||||
Document* doc = PresContext()->Document();
|
||||
if (imgRequestProxy* proxy = url.GetImage()) {
|
||||
if (RefPtr<imgRequestProxy> proxy = url.LoadImage(*doc)) {
|
||||
proxy->Clone(mListener, doc, getter_AddRefs(mContentURLRequest));
|
||||
SetupForContentURLRequest();
|
||||
}
|
||||
|
@ -393,6 +394,9 @@ void nsImageFrame::SetupForContentURLRequest() {
|
|||
return;
|
||||
}
|
||||
|
||||
// We're not using nsStyleImageRequest, so manually track the image.
|
||||
PresContext()->Document()->ImageTracker()->Add(mContentURLRequest);
|
||||
|
||||
uint32_t status = 0;
|
||||
nsresult rv = mContentURLRequest->GetImageStatus(&status);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
|
|
@ -1115,10 +1115,19 @@ void Gecko_SetGradientImageValue(nsStyleImage* aImage,
|
|||
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,
|
||||
const StyleComputedImageUrl* 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) {
|
||||
|
@ -1141,25 +1150,50 @@ void Gecko_InitializeImageCropRect(nsStyleImage* aImage) {
|
|||
nsStyleImage::CropRect{zero, zero, zero, zero}));
|
||||
}
|
||||
|
||||
void Gecko_SetCursorArrayCapacity(nsStyleUI* aUi, size_t aCapacity) {
|
||||
aUi->mCursorImages.Clear();
|
||||
aUi->mCursorImages.SetCapacity(aCapacity);
|
||||
void Gecko_SetCursorArrayLength(nsStyleUI* aStyleUI, size_t aLen) {
|
||||
aStyleUI->mCursorImages.Clear();
|
||||
aStyleUI->mCursorImages.SetLength(aLen);
|
||||
}
|
||||
|
||||
void Gecko_AppendCursorImage(nsStyleUI* aUi,
|
||||
const StyleComputedImageUrl* aUrl) {
|
||||
aUi->mCursorImages.EmplaceBack(*aUrl);
|
||||
void Gecko_SetCursorImageValue(nsCursorImage* aCursor,
|
||||
const StyleComputedImageUrl* aUrl) {
|
||||
MOZ_ASSERT(aCursor && aUrl);
|
||||
|
||||
aCursor->mImage =
|
||||
CreateStyleImageRequest(nsStyleImageRequest::Mode::Discard, aUrl);
|
||||
}
|
||||
|
||||
void Gecko_CopyCursorArrayFrom(nsStyleUI* aDest, const nsStyleUI* aSrc) {
|
||||
aDest->mCursorImages = aSrc->mCursorImages;
|
||||
}
|
||||
|
||||
const nsStyleImageRequest* Gecko_GetImageRequest(const nsStyleImage* aImage) {
|
||||
MOZ_ASSERT(aImage);
|
||||
return aImage->ImageRequest();
|
||||
}
|
||||
|
||||
nsAtom* Gecko_GetImageElement(const nsStyleImage* aImage) {
|
||||
MOZ_ASSERT(aImage && aImage->GetType() == eStyleImageType_Element);
|
||||
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,
|
||||
size_t aElemSize) {
|
||||
auto base = reinterpret_cast<
|
||||
|
@ -1845,6 +1879,11 @@ bool Gecko_AssertClassAttrValueIsSane(const nsAttrValue* aValue) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Gecko_LoadData_DeregisterLoad(const StyleLoadData* aData) {
|
||||
MOZ_ASSERT(aData->load_id != 0);
|
||||
ImageLoader::DeregisterCSSImageFromAllLoaders(*aData);
|
||||
}
|
||||
|
||||
void Gecko_PrintfStderr(const nsCString* aStr) {
|
||||
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_InitializeImageCropRect(nsStyleImage* image);
|
||||
|
||||
const nsStyleImageRequest* Gecko_GetImageRequest(const nsStyleImage* image);
|
||||
nsAtom* Gecko_GetImageElement(const nsStyleImage* image);
|
||||
|
||||
// list-style-image style.
|
||||
|
@ -360,8 +361,11 @@ void Gecko_SetListStyleImageImageValue(
|
|||
void Gecko_CopyListStyleImageFrom(nsStyleList* dest, const nsStyleList* src);
|
||||
|
||||
// cursor style.
|
||||
void Gecko_SetCursorArrayCapacity(nsStyleUI*, size_t);
|
||||
void Gecko_AppendCursorImage(nsStyleUI*, const mozilla::StyleComputedImageUrl*);
|
||||
void Gecko_SetCursorArrayLength(nsStyleUI* ui, size_t len);
|
||||
|
||||
void Gecko_SetCursorImageValue(nsCursorImage* aCursor,
|
||||
const mozilla::StyleComputedImageUrl* url);
|
||||
|
||||
void Gecko_CopyCursorArrayFrom(nsStyleUI* dest, const nsStyleUI* src);
|
||||
|
||||
// Dirtiness tracking.
|
||||
|
@ -502,7 +506,7 @@ float Gecko_FontStretch_ToFloat(mozilla::FontStretch aStretch);
|
|||
void Gecko_FontStretch_SetFloat(mozilla::FontStretch* aStretch,
|
||||
float aFloatValue);
|
||||
|
||||
void Gecko_LoadData_Drop(mozilla::StyleLoadData*);
|
||||
void Gecko_LoadData_DeregisterLoad(const mozilla::StyleLoadData*);
|
||||
|
||||
float Gecko_FontSlantStyle_ToFloat(mozilla::FontSlantStyle aStyle);
|
||||
void Gecko_FontSlantStyle_SetNormal(mozilla::FontSlantStyle*);
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/DocumentInlines.h"
|
||||
#include "mozilla/dom/ImageTracker.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsError.h"
|
||||
|
@ -31,56 +30,15 @@ using namespace mozilla::dom;
|
|||
namespace mozilla {
|
||||
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 */
|
||||
void ImageLoader::Init() {
|
||||
sImages = new GlobalRequestTable();
|
||||
sImageObserver = new GlobalImageObserver();
|
||||
sImages = new nsClassHashtable<nsUint64HashKey, ImageTableEntry>();
|
||||
}
|
||||
|
||||
/* static */
|
||||
void ImageLoader::Shutdown() {
|
||||
delete sImages;
|
||||
sImages = nullptr;
|
||||
sImageObserver = nullptr;
|
||||
}
|
||||
|
||||
void ImageLoader::DropDocumentReference() {
|
||||
|
@ -91,6 +49,21 @@ void ImageLoader::DropDocumentReference() {
|
|||
// been destroyed, and it also calls ClearFrames when it is destroyed.
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -117,31 +90,20 @@ void ImageLoader::AssociateRequestToFrame(imgIRequest* aRequest,
|
|||
nsIFrame* aFrame, FrameFlags aFlags) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
{
|
||||
nsCOMPtr<imgINotificationObserver> observer;
|
||||
aRequest->GetNotificationObserver(getter_AddRefs(observer));
|
||||
if (!observer) {
|
||||
// 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.
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(observer == sImageObserver);
|
||||
nsCOMPtr<imgINotificationObserver> observer;
|
||||
aRequest->GetNotificationObserver(getter_AddRefs(observer));
|
||||
if (!observer) {
|
||||
// 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.
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(observer == this);
|
||||
|
||||
const auto& frameSet =
|
||||
mRequestToFrameMap.LookupForAdd(aRequest).OrInsert([=]() {
|
||||
mDocument->ImageTracker()->Add(aRequest);
|
||||
|
||||
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()) {
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
if (presContext) {
|
||||
nsLayoutUtils::RegisterImageRequestIfAnimated(presContext, aRequest,
|
||||
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.");
|
||||
}
|
||||
|
||||
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,
|
||||
nsIFrame* aFrame) {
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<imgINotificationObserver> observer;
|
||||
aRequest->GetNotificationObserver(getter_AddRefs(observer));
|
||||
MOZ_ASSERT(!observer || observer == sImageObserver);
|
||||
MOZ_ASSERT(!observer || observer == this);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -271,25 +320,15 @@ void ImageLoader::RemoveRequestToFrameMapping(imgIRequest* aRequest,
|
|||
}
|
||||
|
||||
if (frameSet->IsEmpty()) {
|
||||
DeregisterImageRequest(aRequest, GetPresContext());
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
if (presContext) {
|
||||
nsLayoutUtils::DeregisterImageRequest(presContext, aRequest, nullptr);
|
||||
}
|
||||
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,
|
||||
nsIFrame* aFrame) {
|
||||
if (auto entry = mFrameToRequestMap.Lookup(aFrame)) {
|
||||
|
@ -373,7 +412,9 @@ void ImageLoader::ClearFrames(nsPresContext* aPresContext) {
|
|||
}
|
||||
#endif
|
||||
|
||||
DeregisterImageRequest(request, aPresContext);
|
||||
if (aPresContext) {
|
||||
nsLayoutUtils::DeregisterImageRequest(aPresContext, request, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
mRequestToFrameMap.Clear();
|
||||
|
@ -395,12 +436,25 @@ static CORSMode EffectiveCorsMode(nsIURI* aURI,
|
|||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<imgRequestProxy> ImageLoader::LoadImage(
|
||||
const StyleComputedImageUrl& aImage, Document& aLoadingDoc) {
|
||||
void ImageLoader::LoadImage(const StyleComputedImageUrl& aImage,
|
||||
Document& aLoadingDoc) {
|
||||
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();
|
||||
if (!uri) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t loadFlags =
|
||||
|
@ -412,27 +466,13 @@ already_AddRefed<imgRequestProxy> ImageLoader::LoadImage(
|
|||
RefPtr<imgRequestProxy> request;
|
||||
nsresult rv = nsContentUtils::LoadImage(
|
||||
uri, &aLoadingDoc, &aLoadingDoc, data.Principal(), 0, data.ReferrerInfo(),
|
||||
sImageObserver, loadFlags, NS_LITERAL_STRING("css"),
|
||||
getter_AddRefs(request));
|
||||
nullptr, loadFlags, NS_LITERAL_STRING("css"), getter_AddRefs(request));
|
||||
|
||||
if (NS_FAILED(rv) || !request) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
sImages->LookupForAdd(request).OrInsert([] { return new ImageTableEntry(); });
|
||||
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();
|
||||
}
|
||||
entry->mCanonicalRequest = std::move(request);
|
||||
}
|
||||
|
||||
nsPresContext* ImageLoader::GetPresContext() {
|
||||
|
@ -571,8 +611,6 @@ void ImageLoader::RequestReflowOnFrame(FrameWithFlags* aFwf,
|
|||
nsIFrame* frame = aFwf->mFrame;
|
||||
|
||||
// Actually request the reflow.
|
||||
//
|
||||
// FIXME(emilio): Why requesting reflow on the _parent_?
|
||||
nsIFrame* parent = frame->GetInFlowParent();
|
||||
parent->PresShell()->FrameNeedsReflow(parent, IntrinsicDirty::StyleChange,
|
||||
NS_FRAME_IS_DIRTY);
|
||||
|
@ -580,32 +618,21 @@ void ImageLoader::RequestReflowOnFrame(FrameWithFlags* aFwf,
|
|||
// We'll respond to the reflow events by unblocking onload, regardless
|
||||
// of whether the reflow was completed or cancelled. The callback will
|
||||
// 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);
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(ImageLoader)
|
||||
NS_IMPL_RELEASE(ImageLoader)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(ImageLoader)
|
||||
NS_INTERFACE_MAP_ENTRY(imgINotificationObserver)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMETHODIMP
|
||||
GlobalImageObserver::Notify(imgIRequest* aRequest, int32_t aType,
|
||||
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) {
|
||||
ImageLoader::Notify(imgIRequest* aRequest, int32_t aType,
|
||||
const nsIntRect* aData) {
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
nsCString uriString;
|
||||
if (profiler_is_active()) {
|
||||
|
@ -697,7 +724,7 @@ nsresult ImageLoader::OnImageIsAnimated(imgIRequest* aRequest) {
|
|||
}
|
||||
|
||||
nsresult ImageLoader::OnFrameComplete(imgIRequest* aRequest) {
|
||||
if (!mDocument) {
|
||||
if (!mDocument || mInClone) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -718,7 +745,7 @@ nsresult ImageLoader::OnFrameComplete(imgIRequest* aRequest) {
|
|||
}
|
||||
|
||||
nsresult ImageLoader::OnFrameUpdate(imgIRequest* aRequest) {
|
||||
if (!mDocument) {
|
||||
if (!mDocument || mInClone) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -733,7 +760,7 @@ nsresult ImageLoader::OnFrameUpdate(imgIRequest* aRequest) {
|
|||
}
|
||||
|
||||
nsresult ImageLoader::OnLoadComplete(imgIRequest* aRequest) {
|
||||
if (!mDocument) {
|
||||
if (!mDocument || mInClone) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -761,6 +788,30 @@ nsresult ImageLoader::OnLoadComplete(imgIRequest* aRequest) {
|
|||
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() {
|
||||
// Check that the frame is still valid. If it isn't, then onload was
|
||||
// unblocked when the frame was removed from the FrameSet in
|
||||
|
@ -788,5 +839,8 @@ void ImageLoader::ImageReflowCallback::ReflowCallbackCanceled() {
|
|||
delete this;
|
||||
}
|
||||
|
||||
nsClassHashtable<nsUint64HashKey, ImageLoader::ImageTableEntry>*
|
||||
ImageLoader::sImages = nullptr;
|
||||
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "imgIRequest.h"
|
||||
#include "imgINotificationObserver.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/MediaFeatureChange.h"
|
||||
|
||||
class imgIContainer;
|
||||
class nsIFrame;
|
||||
|
@ -37,7 +38,7 @@ namespace css {
|
|||
* NOTE: All methods must be called from the main thread unless otherwise
|
||||
* specified.
|
||||
*/
|
||||
class ImageLoader final {
|
||||
class ImageLoader final : public imgINotificationObserver {
|
||||
public:
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
@ -51,14 +52,17 @@ class ImageLoader final {
|
|||
};
|
||||
|
||||
explicit ImageLoader(dom::Document* aDocument)
|
||||
: mDocument(aDocument) {
|
||||
: mDocument(aDocument), mInClone(false) {
|
||||
MOZ_ASSERT(mDocument);
|
||||
}
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(ImageLoader)
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_IMGINOTIFICATIONOBSERVER
|
||||
|
||||
void DropDocumentReference();
|
||||
|
||||
imgRequestProxy* RegisterCSSImage(const StyleLoadData& aImage);
|
||||
|
||||
void AssociateRequestToFrame(imgIRequest* aRequest, nsIFrame* aFrame,
|
||||
FrameFlags aFlags);
|
||||
|
||||
|
@ -68,24 +72,26 @@ class ImageLoader final {
|
|||
|
||||
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
|
||||
// in because this can be called during presentation destruction after the
|
||||
// presshell pointer on the document has been cleared.
|
||||
void ClearFrames(nsPresContext* aPresContext);
|
||||
|
||||
static already_AddRefed<imgRequestProxy> LoadImage(
|
||||
const StyleComputedImageUrl&, dom::Document&);
|
||||
static void LoadImage(const StyleComputedImageUrl& aImage, dom::Document&);
|
||||
|
||||
static void DeregisterImageFromAllLoaders(imgRequestProxy*);
|
||||
|
||||
// This is called whenever an image we care about notifies the
|
||||
// GlobalImageObserver.
|
||||
nsresult Notify(imgIRequest*, int32_t aType, const nsIntRect* aData);
|
||||
// Cancels the image load for the given LoadData and deregisters it from any
|
||||
// ImageLoaders it was registered with.
|
||||
//
|
||||
// May be called from any thread.
|
||||
static void DeregisterCSSImageFromAllLoaders(const StyleLoadData&);
|
||||
|
||||
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
|
||||
// triggered from an image load.
|
||||
struct ImageReflowCallback final : public nsIReflowCallback {
|
||||
|
@ -155,6 +161,9 @@ class ImageLoader final {
|
|||
void RemoveRequestToFrameMapping(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.
|
||||
RequestToFrameMap mRequestToFrameMap;
|
||||
|
||||
|
@ -163,6 +172,40 @@ class ImageLoader final {
|
|||
|
||||
// A weak pointer to our document. Nulled out by DropDocumentReference.
|
||||
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
|
||||
|
|
|
@ -115,8 +115,6 @@ enum class CallerType : uint32_t;
|
|||
|
||||
class Element;
|
||||
class Document;
|
||||
class ImageTracker;
|
||||
|
||||
} // namespace dom
|
||||
|
||||
namespace ipc {
|
||||
|
@ -177,7 +175,6 @@ struct StyleBox {
|
|||
// Work-around weird cbindgen renaming / avoiding moving stuff outside its
|
||||
// namespace.
|
||||
|
||||
using StyleImageTracker = dom::ImageTracker;
|
||||
using StyleLoader = css::Loader;
|
||||
using StyleLoaderReusableStyleSheets = css::LoaderReusableStyleSheets;
|
||||
using StyleCallerType = dom::CallerType;
|
||||
|
|
|
@ -390,14 +390,12 @@ inline StyleLoadData& StyleCssUrl::LoadData() const {
|
|||
inline nsIURI* StyleCssUrl::GetURI() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
|
||||
auto& loadData = LoadData();
|
||||
if (!(loadData.flags & StyleLoadDataFlags::TRIED_TO_RESOLVE_URI)) {
|
||||
loadData.flags |= StyleLoadDataFlags::TRIED_TO_RESOLVE_URI;
|
||||
RefPtr<nsIURI> resolved;
|
||||
NS_NewURI(getter_AddRefs(resolved), SpecifiedSerialization(), nullptr,
|
||||
ExtraData().BaseURI());
|
||||
loadData.resolved_uri = resolved.forget().take();
|
||||
if (!loadData.tried_to_resolve) {
|
||||
loadData.tried_to_resolve = true;
|
||||
NS_NewURI(getter_AddRefs(loadData.resolved), SpecifiedSerialization(),
|
||||
nullptr, ExtraData().BaseURI());
|
||||
}
|
||||
return loadData.resolved_uri;
|
||||
return loadData.resolved.get();
|
||||
}
|
||||
|
||||
inline nsDependentCSubstring StyleComputedUrl::SpecifiedSerialization() const {
|
||||
|
@ -429,15 +427,6 @@ inline bool StyleComputedUrl::HasRef() const {
|
|||
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 <>
|
||||
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,
|
||||
nsTArray<nsCString>& aURLs) {
|
||||
if (auto* urlValue = aImage.GetURLValue()) {
|
||||
|
@ -664,7 +669,7 @@ static void CollectImageURLsForProperty(nsCSSPropertyID aProp,
|
|||
switch (aProp) {
|
||||
case eCSSProperty_cursor:
|
||||
for (auto& image : aStyle.StyleUI()->mCursorImages) {
|
||||
AddImageURL(image.mImage, aURLs);
|
||||
AddImageURL(*image.mImage, aURLs);
|
||||
}
|
||||
break;
|
||||
case eCSSProperty_background_image:
|
||||
|
@ -673,13 +678,11 @@ static void CollectImageURLsForProperty(nsCSSPropertyID aProp,
|
|||
case eCSSProperty_mask_clip:
|
||||
AddImageURLs(aStyle.StyleSVGReset()->mMask, aURLs);
|
||||
break;
|
||||
case eCSSProperty_list_style_image: {
|
||||
const auto& image = aStyle.StyleList()->mListStyleImage;
|
||||
if (image.IsUrl()) {
|
||||
AddImageURL(image.AsUrl(), aURLs);
|
||||
case eCSSProperty_list_style_image:
|
||||
if (nsStyleImageRequest* image = aStyle.StyleList()->mListStyleImage) {
|
||||
AddImageURL(*image, aURLs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case eCSSProperty_border_image_source:
|
||||
AddImageURL(aStyle.StyleBorder()->mBorderImageSource, aURLs);
|
||||
break;
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include "mozilla/dom/ImageTracker.h"
|
||||
#include "mozilla/CORSMode.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/GeckoBindings.h"
|
||||
#include "mozilla/PreferenceSheet.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "nsIURI.h"
|
||||
|
@ -69,6 +68,19 @@ struct AssertSizeIsLessThan {
|
|||
#include "nsStyleStructList.h"
|
||||
#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 {
|
||||
// This very intentionally avoids comparing LoadData and such.
|
||||
const auto& extra = extra_data.get();
|
||||
|
@ -83,7 +95,11 @@ bool StyleCssUrlData::operator==(const StyleCssUrlData& aOther) const {
|
|||
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 {
|
||||
nsCOMPtr<nsIURI> result = GetURI();
|
||||
|
@ -106,124 +122,56 @@ already_AddRefed<nsIURI> StyleComputedUrl::ResolveLocalRef(
|
|||
return ResolveLocalRef(aContent->GetBaseURI());
|
||||
}
|
||||
|
||||
void StyleComputedUrl::ResolveImage(Document& aDocument,
|
||||
const StyleComputedUrl* aOldImage) {
|
||||
already_AddRefed<imgRequestProxy> StyleComputedUrl::LoadImage(
|
||||
Document& aDocument) {
|
||||
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();
|
||||
if (HasRef()) {
|
||||
bool isEqualExceptRef = false;
|
||||
nsIURI* imageURI = GetURI();
|
||||
if (!imageURI) {
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(imageURI->EqualsExceptRef(docURI, &isEqualExceptRef)) &&
|
||||
isEqualExceptRef) {
|
||||
// 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
|
||||
// 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.
|
||||
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);
|
||||
}
|
||||
StyleLoadData& data = LoadData();
|
||||
if (data.load_id == 0) {
|
||||
data.load_id = sNextLoadID++;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
data.resolved_image = request.forget().take();
|
||||
|
||||
// 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;
|
||||
if (!isPrint) {
|
||||
return do_AddRef(request);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() final {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
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);
|
||||
RefPtr<imgRequestProxy> ret;
|
||||
request->GetStaticRequest(&aDocument, getter_AddRefs(ret));
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
// --------------------
|
||||
|
@ -614,7 +562,6 @@ nsChangeHint nsStyleOutline::CalcDifference(
|
|||
nsStyleList::nsStyleList(const Document& aDocument)
|
||||
: mListStylePosition(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE),
|
||||
mQuotes(StyleQuotes::Auto()),
|
||||
mListStyleImage(StyleImageUrlOrNone::None()),
|
||||
mImageRegion(StyleClipRectOrAuto::Auto()),
|
||||
mMozListReversed(StyleMozListReversed::False) {
|
||||
MOZ_COUNT_CTOR(nsStyleList);
|
||||
|
@ -627,9 +574,9 @@ nsStyleList::~nsStyleList() { MOZ_COUNT_DTOR(nsStyleList); }
|
|||
|
||||
nsStyleList::nsStyleList(const nsStyleList& aSource)
|
||||
: mListStylePosition(aSource.mListStylePosition),
|
||||
mListStyleImage(aSource.mListStyleImage),
|
||||
mCounterStyle(aSource.mCounterStyle),
|
||||
mQuotes(aSource.mQuotes),
|
||||
mListStyleImage(aSource.mListStyleImage),
|
||||
mImageRegion(aSource.mImageRegion),
|
||||
mMozListReversed(aSource.mMozListReversed) {
|
||||
MOZ_COUNT_CTOR(nsStyleList);
|
||||
|
@ -639,12 +586,9 @@ void nsStyleList::TriggerImageLoads(Document& aDocument,
|
|||
const nsStyleList* aOldStyle) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mListStyleImage.IsUrl() && !mListStyleImage.AsUrl().IsImageResolved()) {
|
||||
auto* oldUrl = aOldStyle && aOldStyle->mListStyleImage.IsUrl()
|
||||
? &aOldStyle->mListStyleImage.AsUrl()
|
||||
: nullptr;
|
||||
const_cast<StyleComputedImageUrl&>(mListStyleImage.AsUrl())
|
||||
.ResolveImage(aDocument, oldUrl);
|
||||
if (mListStyleImage && !mListStyleImage->IsResolved()) {
|
||||
mListStyleImage->Resolve(
|
||||
aDocument, aOldStyle ? aOldStyle->mListStyleImage.get() : nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -680,7 +624,7 @@ nsChangeHint nsStyleList::CalcDifference(
|
|||
}
|
||||
// list-style-image and -moz-image-region may affect some XUL elements
|
||||
// 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;
|
||||
}
|
||||
if (mImageRegion != aNewData.mImageRegion) {
|
||||
|
@ -695,11 +639,11 @@ nsChangeHint nsStyleList::CalcDifference(
|
|||
}
|
||||
|
||||
already_AddRefed<nsIURI> nsStyleList::GetListStyleImageURI() const {
|
||||
if (!mListStyleImage.IsUrl()) {
|
||||
if (!mListStyleImage) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri = mListStyleImage.AsUrl().GetURI();
|
||||
nsCOMPtr<nsIURI> uri = mListStyleImage->GetImageURI();
|
||||
return uri.forget();
|
||||
}
|
||||
|
||||
|
@ -1578,6 +1522,154 @@ bool StyleGradient::IsOpaque() const {
|
|||
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
|
||||
//
|
||||
|
@ -1628,7 +1720,8 @@ imgIContainer* CachedBorderImageData::GetSubImage(uint8_t aIndex) {
|
|||
// nsStyleImage
|
||||
//
|
||||
|
||||
nsStyleImage::nsStyleImage() : mCropRect(nullptr), mType(eStyleImageType_Null) {
|
||||
nsStyleImage::nsStyleImage()
|
||||
: mType(eStyleImageType_Null), mImage(nullptr), mCropRect(nullptr) {
|
||||
MOZ_COUNT_CTOR(nsStyleImage);
|
||||
}
|
||||
|
||||
|
@ -1640,7 +1733,7 @@ nsStyleImage::~nsStyleImage() {
|
|||
}
|
||||
|
||||
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
|
||||
// to copy the reference count
|
||||
MOZ_COUNT_CTOR(nsStyleImage);
|
||||
|
@ -1659,7 +1752,7 @@ void nsStyleImage::DoCopy(const nsStyleImage& aOther) {
|
|||
SetNull();
|
||||
|
||||
if (aOther.mType == eStyleImageType_Image) {
|
||||
SetImageUrl(aOther.mImage);
|
||||
SetImageRequest(do_AddRef(aOther.mImage));
|
||||
} else if (aOther.mType == eStyleImageType_Gradient) {
|
||||
SetGradientData(MakeUnique<StyleGradient>(*aOther.mGradient));
|
||||
} else if (aOther.mType == eStyleImageType_Element) {
|
||||
|
@ -1678,7 +1771,7 @@ void nsStyleImage::SetNull() {
|
|||
delete mGradient;
|
||||
mGradient = nullptr;
|
||||
} else if (mType == eStyleImageType_Image) {
|
||||
mImage.~StyleComputedImageUrl();
|
||||
NS_RELEASE(mImage);
|
||||
} else if (mType == eStyleImageType_Element) {
|
||||
NS_RELEASE(mElementId);
|
||||
}
|
||||
|
@ -1687,14 +1780,18 @@ void nsStyleImage::SetNull() {
|
|||
mCropRect = nullptr;
|
||||
}
|
||||
|
||||
void nsStyleImage::SetImageUrl(const StyleComputedImageUrl& aImage) {
|
||||
void nsStyleImage::SetImageRequest(
|
||||
already_AddRefed<nsStyleImageRequest> aImage) {
|
||||
RefPtr<nsStyleImageRequest> image = aImage;
|
||||
|
||||
if (mType != eStyleImageType_Null) {
|
||||
SetNull();
|
||||
}
|
||||
|
||||
new (&mImage) StyleComputedImageUrl(aImage);
|
||||
mType = eStyleImageType_Image;
|
||||
|
||||
if (image) {
|
||||
mImage = image.forget().take();
|
||||
mType = eStyleImageType_Image;
|
||||
}
|
||||
if (mCachedBIData) {
|
||||
mCachedBIData->PurgeCachedImages();
|
||||
}
|
||||
|
@ -1740,6 +1837,22 @@ static int32_t ConvertToPixelCoord(const StyleNumberOrPercentage& aCoord,
|
|||
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* aIsEntireImage) const {
|
||||
MOZ_ASSERT(mType == eStyleImageType_Image,
|
||||
|
@ -1896,7 +2009,7 @@ bool nsStyleImage::operator==(const nsStyleImage& aOther) const {
|
|||
}
|
||||
|
||||
if (mType == eStyleImageType_Image) {
|
||||
return mImage == aOther.mImage;
|
||||
return DefinitelyEqualImages(mImage, aOther.mImage);
|
||||
}
|
||||
|
||||
if (mType == eStyleImageType_Gradient) {
|
||||
|
@ -1933,12 +2046,12 @@ already_AddRefed<nsIURI> nsStyleImage::GetImageURI() const {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri = mImage.GetURI();
|
||||
nsCOMPtr<nsIURI> uri = mImage->GetImageURI();
|
||||
return uri.forget();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
//
|
||||
|
@ -3417,8 +3501,8 @@ LogicalSide nsStyleText::TextEmphasisSide(WritingMode aWM) const {
|
|||
// nsStyleUI
|
||||
//
|
||||
|
||||
nsCursorImage::nsCursorImage(const StyleComputedImageUrl& aImage)
|
||||
: mHaveHotspot(false), mHotspotX(0.0f), mHotspotY(0.0f), mImage(aImage) {}
|
||||
nsCursorImage::nsCursorImage()
|
||||
: mHaveHotspot(false), mHotspotX(0.0f), mHotspotY(0.0f) {}
|
||||
|
||||
nsCursorImage::nsCursorImage(const nsCursorImage& aOther)
|
||||
: mHaveHotspot(aOther.mHaveHotspot),
|
||||
|
@ -3444,7 +3528,8 @@ bool nsCursorImage::operator==(const nsCursorImage& aOther) const {
|
|||
aOther.mHaveHotspot || (aOther.mHotspotX == 0 && aOther.mHotspotY == 0),
|
||||
"expected mHotspot{X,Y} to be 0 when mHaveHotspot is false");
|
||||
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)
|
||||
|
@ -3479,13 +3564,13 @@ void nsStyleUI::TriggerImageLoads(Document& aDocument,
|
|||
for (size_t i = 0; i < mCursorImages.Length(); ++i) {
|
||||
nsCursorImage& cursor = mCursorImages[i];
|
||||
|
||||
if (!cursor.mImage.IsImageResolved()) {
|
||||
if (cursor.mImage && !cursor.mImage->IsResolved()) {
|
||||
const nsCursorImage* oldCursor =
|
||||
(aOldStyle && aOldStyle->mCursorImages.Length() > i)
|
||||
? &aOldStyle->mCursorImages[i]
|
||||
: nullptr;
|
||||
cursor.mImage.ResolveImage(aDocument,
|
||||
oldCursor ? &oldCursor->mImage : nullptr);
|
||||
cursor.mImage->Resolve(aDocument,
|
||||
oldCursor ? oldCursor->mImage.get() : nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,6 +133,96 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleFont {
|
|||
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 {
|
||||
eStyleImageType_Null,
|
||||
eStyleImageType_Image,
|
||||
|
@ -178,34 +268,36 @@ struct nsStyleImage {
|
|||
nsStyleImage& operator=(const nsStyleImage& aOther);
|
||||
|
||||
void SetNull();
|
||||
void SetImageUrl(const mozilla::StyleComputedImageUrl&);
|
||||
void SetImageRequest(already_AddRefed<nsStyleImageRequest> aImage);
|
||||
void SetGradientData(mozilla::UniquePtr<mozilla::StyleGradient>);
|
||||
void SetElementId(already_AddRefed<nsAtom> aElementId);
|
||||
void SetCropRect(mozilla::UniquePtr<CropRect> aCropRect);
|
||||
|
||||
void ResolveImage(mozilla::dom::Document& aDocument,
|
||||
const nsStyleImage* aOldImage) {
|
||||
if (mType == eStyleImageType_Image && !mImage.IsImageResolved()) {
|
||||
const auto* oldRequest =
|
||||
MOZ_ASSERT(mType != eStyleImageType_Image || mImage);
|
||||
if (mType == eStyleImageType_Image && !mImage->IsResolved()) {
|
||||
const nsStyleImageRequest* oldRequest =
|
||||
(aOldImage && aOldImage->GetType() == eStyleImageType_Image)
|
||||
? &aOldImage->ImageUrl()
|
||||
? aOldImage->ImageRequest()
|
||||
: nullptr;
|
||||
mImage.ResolveImage(aDocument, oldRequest);
|
||||
mImage->Resolve(aDocument, oldRequest);
|
||||
}
|
||||
}
|
||||
|
||||
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(mImage);
|
||||
return mImage;
|
||||
}
|
||||
imgRequestProxy* GetImageData() const { return ImageUrl().GetImage(); }
|
||||
imgRequestProxy* GetImageData() const { return ImageRequest()->get(); }
|
||||
const mozilla::StyleGradient& GetGradient() const {
|
||||
NS_ASSERTION(mType == eStyleImageType_Gradient, "Data is not a gradient!");
|
||||
return *mGradient;
|
||||
}
|
||||
bool IsResolved() const {
|
||||
return mType != eStyleImageType_Image || ImageUrl().IsImageResolved();
|
||||
return mType != eStyleImageType_Image || ImageRequest()->IsResolved();
|
||||
}
|
||||
const nsAtom* GetElementId() const {
|
||||
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.
|
||||
mozilla::UniquePtr<CachedBorderImageData> mCachedBIData;
|
||||
|
||||
// This is _currently_ used only in conjunction with eStyleImageType_Image.
|
||||
mozilla::UniquePtr<CropRect> mCropRect;
|
||||
|
||||
nsStyleImageType mType;
|
||||
union {
|
||||
mozilla::StyleComputedImageUrl mImage;
|
||||
nsStyleImageRequest* mImage;
|
||||
mozilla::StyleGradient* mGradient;
|
||||
nsAtom* mElementId;
|
||||
};
|
||||
|
||||
// This is _currently_ used only in conjunction with eStyleImageType_Image.
|
||||
mozilla::UniquePtr<CropRect> mCropRect;
|
||||
};
|
||||
|
||||
struct nsStyleImageLayers {
|
||||
|
@ -828,10 +920,6 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList {
|
|||
nsStyleList(const nsStyleList& aStyleList);
|
||||
~nsStyleList();
|
||||
|
||||
private:
|
||||
nsStyleList& operator=(const nsStyleList& aOther) = delete;
|
||||
|
||||
public:
|
||||
void TriggerImageLoads(mozilla::dom::Document&, const nsStyleList*);
|
||||
static constexpr bool kHasTriggerImageLoads = true;
|
||||
|
||||
|
@ -839,8 +927,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList {
|
|||
const nsStyleDisplay& aOldDisplay) const;
|
||||
|
||||
imgRequestProxy* GetListStyleImage() const {
|
||||
return mListStyleImage.IsUrl() ? mListStyleImage.AsUrl().GetImage()
|
||||
: nullptr;
|
||||
return mListStyleImage ? mListStyleImage->get() : nullptr;
|
||||
}
|
||||
|
||||
nsRect GetImageRegion() const {
|
||||
|
@ -853,15 +940,18 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList {
|
|||
already_AddRefed<nsIURI> GetListStyleImageURI() const;
|
||||
|
||||
uint8_t mListStylePosition;
|
||||
RefPtr<nsStyleImageRequest> mListStyleImage;
|
||||
|
||||
mozilla::CounterStylePtr mCounterStyle;
|
||||
mozilla::StyleQuotes mQuotes;
|
||||
mozilla::StyleImageUrlOrNone mListStyleImage;
|
||||
|
||||
// the rect to use within an image.
|
||||
mozilla::StyleClipRectOrAuto mImageRegion;
|
||||
// true in an <ol reversed> scope.
|
||||
mozilla::StyleMozListReversed mMozListReversed;
|
||||
private:
|
||||
nsStyleList& operator=(const nsStyleList& aOther) = delete;
|
||||
|
||||
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 {
|
||||
|
@ -1829,9 +1919,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleContent {
|
|||
explicit nsStyleContent(const mozilla::dom::Document&);
|
||||
nsStyleContent(const nsStyleContent& aContent);
|
||||
~nsStyleContent();
|
||||
|
||||
void TriggerImageLoads(mozilla::dom::Document&, const nsStyleContent*);
|
||||
static constexpr bool kHasTriggerImageLoads = true;
|
||||
static constexpr bool kHasTriggerImageLoads = false;
|
||||
|
||||
size_t ContentCount() const {
|
||||
return mContent.IsItems() ? mContent.AsItems().Length() : 0;
|
||||
|
@ -1871,10 +1959,10 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUIReset {
|
|||
struct nsCursorImage {
|
||||
bool mHaveHotspot;
|
||||
float mHotspotX, mHotspotY;
|
||||
mozilla::StyleComputedImageUrl mImage;
|
||||
RefPtr<nsStyleImageRequest> mImage;
|
||||
|
||||
explicit nsCursorImage(const mozilla::StyleComputedImageUrl&);
|
||||
nsCursorImage(const nsCursorImage&);
|
||||
nsCursorImage();
|
||||
nsCursorImage(const nsCursorImage& aOther);
|
||||
|
||||
nsCursorImage& operator=(const nsCursorImage& aOther);
|
||||
|
||||
|
@ -1883,7 +1971,7 @@ struct nsCursorImage {
|
|||
return !(*this == aOther);
|
||||
}
|
||||
|
||||
imgRequestProxy* GetImage() const { return mImage.GetImage(); }
|
||||
imgRequestProxy* GetImage() const { return mImage->get(); }
|
||||
};
|
||||
|
||||
struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUI {
|
||||
|
|
|
@ -876,16 +876,17 @@ void SVGMaskObserverList::ResolveImage(uint32_t aIndex) {
|
|||
const nsStyleSVGReset* svgReset = mFrame->StyleSVGReset();
|
||||
MOZ_ASSERT(aIndex < svgReset->mMask.mImageCount);
|
||||
|
||||
auto& image =
|
||||
nsStyleImage& image =
|
||||
const_cast<nsStyleImage&>(svgReset->mMask.mLayers[aIndex].mImage);
|
||||
|
||||
if (!image.IsResolved()) {
|
||||
MOZ_ASSERT(image.GetType() == nsStyleImageType::eStyleImageType_Image);
|
||||
image.ResolveImage(*mFrame->PresContext()->Document(), nullptr);
|
||||
|
||||
Document* doc = mFrame->PresContext()->Document();
|
||||
mozilla::css::ImageLoader* imageLoader =
|
||||
mFrame->PresContext()->Document()->StyleImageLoader();
|
||||
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::stylesheets::RulesMutateError;
|
||||
use crate::values::computed::transform::Matrix3D;
|
||||
use crate::values::computed::url::ComputedImageUrl;
|
||||
use crate::values::computed::{Gradient, Image, TextAlign};
|
||||
use crate::values::generics::image::GenericImage;
|
||||
use crate::values::generics::rect::Rect;
|
||||
|
@ -62,7 +63,7 @@ impl nsStyleImage {
|
|||
match self.mType {
|
||||
nsStyleImageType::eStyleImageType_Null => None,
|
||||
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() {
|
||||
Some(GenericImage::Url(url))
|
||||
} 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 {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
use crate::gecko_bindings::bindings;
|
||||
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::stylesheets::{CorsMode, UrlExtraData};
|
||||
use crate::values::computed::{Context, ToComputedValue};
|
||||
|
@ -148,52 +150,31 @@ struct LoadDataKey(*const LoadDataSource);
|
|||
unsafe impl Sync for LoadDataKey {}
|
||||
unsafe impl Send for LoadDataKey {}
|
||||
|
||||
bitflags! {
|
||||
/// 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.
|
||||
/// The load data for a given URL. This is mutable from C++, for now at least.
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct LoadData {
|
||||
/// A strong reference to the imgRequestProxy, if any, that should be
|
||||
/// released on drop.
|
||||
///
|
||||
/// 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,
|
||||
resolved: RefPtr<structs::nsIURI>,
|
||||
load_id: u64,
|
||||
tried_to_resolve: bool,
|
||||
}
|
||||
|
||||
impl Drop for LoadData {
|
||||
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 {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
resolved_image: std::ptr::null_mut(),
|
||||
resolved_uri: std::ptr::null_mut(),
|
||||
flags: LoadDataFlags::empty(),
|
||||
resolved: RefPtr::null(),
|
||||
load_id: 0,
|
||||
tried_to_resolve: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -361,6 +342,13 @@ impl ToCss for ComputedUrl {
|
|||
#[repr(transparent)]
|
||||
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 {
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
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_CopyFontFamilyFrom;
|
||||
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_SetCursorArrayLength;
|
||||
use crate::gecko_bindings::bindings::Gecko_SetCursorImageValue;
|
||||
use crate::gecko_bindings::bindings::Gecko_nsStyleFont_SetLang;
|
||||
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::structs;
|
||||
use crate::gecko_bindings::structs::nsCSSPropertyID;
|
||||
|
@ -48,6 +53,7 @@ use crate::values::computed::BorderStyle;
|
|||
use crate::values::computed::font::FontSize;
|
||||
use crate::values::generics::column::ColumnCount;
|
||||
use crate::values::generics::image::ImageLayer;
|
||||
use crate::values::generics::url::UrlOrNone;
|
||||
|
||||
|
||||
pub mod style_structs {
|
||||
|
@ -2102,7 +2108,43 @@ fn static_assert() {
|
|||
<% impl_simple_image_array_property("blend_mode", "background", "mImage", "mBlendMode", "Background") %>
|
||||
</%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) {
|
||||
use nsstring::{nsACString, nsCStr};
|
||||
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) {
|
||||
self.gecko.mCursor = v.keyword;
|
||||
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() {
|
||||
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 {
|
||||
|
@ -2428,7 +2473,10 @@ clip-path
|
|||
let keyword = self.gecko.mCursor;
|
||||
|
||||
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 =
|
||||
if gecko_cursor_image.mHaveHotspot {
|
||||
|
|
|
@ -170,7 +170,6 @@ include = [
|
|||
"ComputedUrl",
|
||||
"ComputedImageUrl",
|
||||
"UrlOrNone",
|
||||
"ImageUrlOrNone",
|
||||
"Filter",
|
||||
"Gradient",
|
||||
"GridTemplateAreas",
|
||||
|
@ -207,7 +206,6 @@ renaming_overrides_prefixing = true
|
|||
"nscolor" = "nscolor"
|
||||
"nsAtom" = "nsAtom"
|
||||
"nsIURI" = "nsIURI"
|
||||
"imgRequestProxy" = "imgRequestProxy"
|
||||
"nsCompatibility" = "nsCompatibility"
|
||||
"SharedFontList" = "SharedFontList"
|
||||
"nsSimpleContentList" = "nsSimpleContentList"
|
||||
|
@ -653,11 +651,7 @@ renaming_overrides_prefixing = true
|
|||
inline StyleCorsMode CorsMode() const;
|
||||
already_AddRefed<nsIURI> ResolveLocalRef(nsIURI* aBase) const;
|
||||
already_AddRefed<nsIURI> ResolveLocalRef(const nsIContent* aContent) const;
|
||||
|
||||
// Only relevant for images.
|
||||
inline bool IsImageResolved() const;
|
||||
inline imgRequestProxy* GetImage() const;
|
||||
void ResolveImage(dom::Document&, const StyleComputedUrl* aOldImage);
|
||||
already_AddRefed<imgRequestProxy> LoadImage(mozilla::dom::Document&);
|
||||
"""
|
||||
|
||||
"GenericGradient" = """
|
||||
|
|
Загрузка…
Ссылка в новой задаче