Bug 1606628 - Remove nsStyleImageRequest. r=tnikkel,heycam

This removes nsStyleImageRequest by moving the load state to LoadData instead
(where other lazy state like the resolved URL and load id lives).

That way we can use cbindgen for more stuff (there's no blocker for using it for
all images now), and we can undo the image tracking shenanigans that I had to do
in bug 1605803 in nsImageFrame.

This removes the mDocGroup member because well, there's no real upside of that
now that quantum DOM is not a thing.

It also removes the static clones of the image requests, and the need for each
computed value instance to have its own request. These were needed because we
needed the image loader for the particular document to observe the image
changes. But we were also tracking the request -> loader for other purposes.
Instead, Now all the images get loaded with GlobalImageObserver as a listener,
which looks in the image map and forwards the notification to all the interested
loaders instead dynamically.

The style value is only responsible to load the image, and no longer tracks /
locks it. Instead, the loader does so, via the image tracker.

Differential Revision: https://phabricator.services.mozilla.com/D58519

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Emilio Cobos Álvarez 2020-02-07 20:36:34 +00:00
parent 0f65e363cb
commit 374cabd6e7
18 changed files with 454 additions and 764 deletions

View File

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

View File

@ -1525,7 +1525,6 @@ 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.

View File

@ -17,6 +17,7 @@
#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 +1164,7 @@ void nsFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
MaybeScheduleReflowSVGNonDisplayText(this);
Document* doc = PresContext()->Document();
ImageLoader* imageLoader = doc->StyleImageLoader();
ImageLoader* loader = 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 +1184,12 @@ void nsFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
aOldComputedStyle ? &aOldComputedStyle->StyleBackground()->mImage
: nullptr;
const nsStyleImageLayers* newLayers = &StyleBackground()->mImage;
AddAndRemoveImageAssociations(*imageLoader, this, oldLayers, newLayers);
AddAndRemoveImageAssociations(*loader, this, oldLayers, newLayers);
oldLayers =
aOldComputedStyle ? &aOldComputedStyle->StyleSVGReset()->mMask : nullptr;
newLayers = &StyleSVGReset()->mMask;
AddAndRemoveImageAssociations(*imageLoader, this, oldLayers, newLayers);
AddAndRemoveImageAssociations(*loader, this, oldLayers, newLayers);
const nsStyleDisplay* disp = StyleDisplay();
bool handleStickyChange = false;
@ -1315,10 +1316,10 @@ void nsFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
if (oldBorderImage != newBorderImage) {
// stop and restart the image loading/notification
if (oldBorderImage && HasImageRequest()) {
imageLoader->DisassociateRequestFromFrame(oldBorderImage, this);
loader->DisassociateRequestFromFrame(oldBorderImage, this);
}
if (newBorderImage) {
imageLoader->AssociateRequestToFrame(newBorderImage, this, 0);
loader->AssociateRequestToFrame(newBorderImage, this, 0);
}
}
@ -1331,11 +1332,11 @@ void nsFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
if (oldShapeImage != newShapeImage) {
if (oldShapeImage && HasImageRequest()) {
imageLoader->DisassociateRequestFromFrame(oldShapeImage, this);
loader->DisassociateRequestFromFrame(oldShapeImage, this);
}
if (newShapeImage) {
imageLoader->AssociateRequestToFrame(
newShapeImage, this, ImageLoader::REQUEST_REQUIRES_REFLOW);
loader->AssociateRequestToFrame(newShapeImage, this,
ImageLoader::REQUEST_REQUIRES_REFLOW);
}
}

View File

@ -272,7 +272,6 @@ 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);
@ -368,7 +367,7 @@ void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
auto& url = const_cast<StyleComputedUrl&>(
styleContent->ContentAt(contentIndex).AsUrl());
Document* doc = PresContext()->Document();
if (RefPtr<imgRequestProxy> proxy = url.LoadImage(*doc)) {
if (imgRequestProxy* proxy = url.GetImage()) {
proxy->Clone(mListener, doc, getter_AddRefs(mContentURLRequest));
SetupForContentURLRequest();
}
@ -394,9 +393,6 @@ 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)) {

View File

@ -1115,19 +1115,10 @@ 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);
RefPtr<nsStyleImageRequest> req =
CreateStyleImageRequest(nsStyleImageRequest::Mode::Track, aUrl);
aImage->SetImageRequest(req.forget());
aImage->SetImageUrl(*aUrl);
}
void Gecko_SetImageElement(nsStyleImage* aImage, nsAtom* aAtom) {
@ -1150,50 +1141,25 @@ void Gecko_InitializeImageCropRect(nsStyleImage* aImage) {
nsStyleImage::CropRect{zero, zero, zero, zero}));
}
void Gecko_SetCursorArrayLength(nsStyleUI* aStyleUI, size_t aLen) {
aStyleUI->mCursorImages.Clear();
aStyleUI->mCursorImages.SetLength(aLen);
void Gecko_SetCursorArrayCapacity(nsStyleUI* aUi, size_t aCapacity) {
aUi->mCursorImages.Clear();
aUi->mCursorImages.SetCapacity(aCapacity);
}
void Gecko_SetCursorImageValue(nsCursorImage* aCursor,
const StyleComputedImageUrl* aUrl) {
MOZ_ASSERT(aCursor && aUrl);
aCursor->mImage =
CreateStyleImageRequest(nsStyleImageRequest::Mode::Discard, aUrl);
void Gecko_AppendCursorImage(nsStyleUI* aUi,
const StyleComputedImageUrl* aUrl) {
aUi->mCursorImages.EmplaceBack(*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<
@ -1879,11 +1845,6 @@ 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());
}

View File

@ -349,7 +349,6 @@ 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.
@ -361,11 +360,8 @@ void Gecko_SetListStyleImageImageValue(
void Gecko_CopyListStyleImageFrom(nsStyleList* dest, const nsStyleList* src);
// cursor style.
void Gecko_SetCursorArrayLength(nsStyleUI* ui, size_t len);
void Gecko_SetCursorImageValue(nsCursorImage* aCursor,
const mozilla::StyleComputedImageUrl* url);
void Gecko_SetCursorArrayCapacity(nsStyleUI*, size_t);
void Gecko_AppendCursorImage(nsStyleUI*, const mozilla::StyleComputedImageUrl*);
void Gecko_CopyCursorArrayFrom(nsStyleUI* dest, const nsStyleUI* src);
// Dirtiness tracking.
@ -506,7 +502,7 @@ float Gecko_FontStretch_ToFloat(mozilla::FontStretch aStretch);
void Gecko_FontStretch_SetFloat(mozilla::FontStretch* aStretch,
float aFloatValue);
void Gecko_LoadData_DeregisterLoad(const mozilla::StyleLoadData*);
void Gecko_LoadData_Drop(mozilla::StyleLoadData*);
float Gecko_FontSlantStyle_ToFloat(mozilla::FontSlantStyle aStyle);
void Gecko_FontSlantStyle_SetNormal(mozilla::FontSlantStyle*);

View File

@ -12,6 +12,7 @@
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/ImageTracker.h"
#include "nsContentUtils.h"
#include "nsLayoutUtils.h"
#include "nsError.h"
@ -30,15 +31,59 @@ 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;
// The amount of style values that are sharing this image.
uint32_t mSharedCount = 1;
};
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 nsClassHashtable<nsUint64HashKey, ImageTableEntry>();
sImages = new GlobalRequestTable();
sImageObserver = new GlobalImageObserver();
}
/* static */
void ImageLoader::Shutdown() {
delete sImages;
sImages = nullptr;
sImageObserver = nullptr;
}
void ImageLoader::DropDocumentReference() {
@ -49,21 +94,6 @@ 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;
}
@ -90,20 +120,31 @@ 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;
{
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);
}
MOZ_ASSERT(observer == this);
const auto& frameSet =
mRequestToFrameMap.LookupForAdd(aRequest).OrInsert([=]() {
nsPresContext* presContext = GetPresContext();
if (presContext) {
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()) {
nsLayoutUtils::RegisterImageRequestIfAnimated(presContext, aRequest,
nullptr);
}
@ -204,100 +245,13 @@ 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 == this);
MOZ_ASSERT(!observer || observer == sImageObserver);
}
#endif
@ -320,15 +274,25 @@ void ImageLoader::RemoveRequestToFrameMapping(imgIRequest* aRequest,
}
if (frameSet->IsEmpty()) {
nsPresContext* presContext = GetPresContext();
if (presContext) {
nsLayoutUtils::DeregisterImageRequest(presContext, aRequest, nullptr);
}
DeregisterImageRequest(aRequest, GetPresContext());
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)) {
@ -412,9 +376,7 @@ void ImageLoader::ClearFrames(nsPresContext* aPresContext) {
}
#endif
if (aPresContext) {
nsLayoutUtils::DeregisterImageRequest(aPresContext, request, nullptr);
}
DeregisterImageRequest(request, aPresContext);
}
mRequestToFrameMap.Clear();
@ -436,25 +398,12 @@ static CORSMode EffectiveCorsMode(nsIURI* aURI,
}
/* static */
void ImageLoader::LoadImage(const StyleComputedImageUrl& aImage,
Document& aLoadingDoc) {
already_AddRefed<imgRequestProxy> 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;
return nullptr;
}
int32_t loadFlags =
@ -466,13 +415,47 @@ void ImageLoader::LoadImage(const StyleComputedImageUrl& aImage,
RefPtr<imgRequestProxy> request;
nsresult rv = nsContentUtils::LoadImage(
uri, &aLoadingDoc, &aLoadingDoc, data.Principal(), 0, data.ReferrerInfo(),
nullptr, loadFlags, NS_LITERAL_STRING("css"), getter_AddRefs(request));
sImageObserver, loadFlags, NS_LITERAL_STRING("css"),
getter_AddRefs(request));
if (NS_FAILED(rv) || !request) {
return nullptr;
}
sImages->LookupForAdd(request).OrInsert([] { return new ImageTableEntry(); });
return request.forget();
}
void ImageLoader::UnloadImage(imgRequestProxy* aImage) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aImage);
auto lookup = sImages->Lookup(aImage);
MOZ_DIAGNOSTIC_ASSERT(lookup, "Unregistered image?");
if (MOZ_UNLIKELY(!lookup)) {
return;
}
entry->mCanonicalRequest = std::move(request);
if (MOZ_UNLIKELY(--lookup.Data()->mSharedCount)) {
// Someone else still cares about this image.
return;
}
aImage->CancelAndForgetObserver(NS_BINDING_ABORTED);
lookup.Remove();
}
void ImageLoader::NoteSharedLoad(imgRequestProxy* aImage) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aImage);
auto lookup = sImages->Lookup(aImage);
MOZ_DIAGNOSTIC_ASSERT(lookup, "Unregistered image?");
if (MOZ_UNLIKELY(!lookup)) {
return;
}
lookup.Data()->mSharedCount++;
}
nsPresContext* ImageLoader::GetPresContext() {
@ -611,6 +594,8 @@ 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);
@ -618,21 +603,32 @@ 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.
ImageReflowCallback* unblocker =
new ImageReflowCallback(this, frame, aRequest);
auto* 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
ImageLoader::Notify(imgIRequest* aRequest, int32_t aType,
const nsIntRect* aData) {
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) {
#ifdef MOZ_GECKO_PROFILER
nsCString uriString;
if (profiler_is_active()) {
@ -724,7 +720,7 @@ nsresult ImageLoader::OnImageIsAnimated(imgIRequest* aRequest) {
}
nsresult ImageLoader::OnFrameComplete(imgIRequest* aRequest) {
if (!mDocument || mInClone) {
if (!mDocument) {
return NS_OK;
}
@ -745,7 +741,7 @@ nsresult ImageLoader::OnFrameComplete(imgIRequest* aRequest) {
}
nsresult ImageLoader::OnFrameUpdate(imgIRequest* aRequest) {
if (!mDocument || mInClone) {
if (!mDocument) {
return NS_OK;
}
@ -760,7 +756,7 @@ nsresult ImageLoader::OnFrameUpdate(imgIRequest* aRequest) {
}
nsresult ImageLoader::OnLoadComplete(imgIRequest* aRequest) {
if (!mDocument || mInClone) {
if (!mDocument) {
return NS_OK;
}
@ -788,30 +784,6 @@ 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
@ -839,8 +811,5 @@ void ImageLoader::ImageReflowCallback::ReflowCallbackCanceled() {
delete this;
}
nsClassHashtable<nsUint64HashKey, ImageLoader::ImageTableEntry>*
ImageLoader::sImages = nullptr;
} // namespace css
} // namespace mozilla

View File

@ -19,7 +19,6 @@
#include "imgIRequest.h"
#include "imgINotificationObserver.h"
#include "mozilla/Attributes.h"
#include "mozilla/MediaFeatureChange.h"
class imgIContainer;
class nsIFrame;
@ -38,7 +37,7 @@ namespace css {
* NOTE: All methods must be called from the main thread unless otherwise
* specified.
*/
class ImageLoader final : public imgINotificationObserver {
class ImageLoader final {
public:
static void Init();
static void Shutdown();
@ -52,17 +51,14 @@ class ImageLoader final : public imgINotificationObserver {
};
explicit ImageLoader(dom::Document* aDocument)
: mDocument(aDocument), mInClone(false) {
: mDocument(aDocument) {
MOZ_ASSERT(mDocument);
}
NS_DECL_ISUPPORTS
NS_DECL_IMGINOTIFICATIONOBSERVER
NS_INLINE_DECL_REFCOUNTING(ImageLoader)
void DropDocumentReference();
imgRequestProxy* RegisterCSSImage(const StyleLoadData& aImage);
void AssociateRequestToFrame(imgIRequest* aRequest, nsIFrame* aFrame,
FrameFlags aFlags);
@ -72,26 +68,34 @@ class ImageLoader final : public imgINotificationObserver {
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 void LoadImage(const StyleComputedImageUrl& aImage, dom::Document&);
// Triggers an image load.
static already_AddRefed<imgRequestProxy> LoadImage(
const StyleComputedImageUrl&, dom::Document&);
// Cancels the image load for the given LoadData and deregisters it from any
// ImageLoaders it was registered with.
// Usually, only one style value owns a given proxy. However, we have a hack
// to share image proxies in chrome documents under some circumstances. We
// need to keep track of this so that we don't stop tracking images too early.
//
// May be called from any thread.
static void DeregisterCSSImageFromAllLoaders(const StyleLoadData&);
// In practice it shouldn't matter as these chrome images are mostly static,
// but it is always good to keep sanity.
static void NoteSharedLoad(imgRequestProxy*);
// Undoes what `LoadImage` does.
static void UnloadImage(imgRequestProxy*);
// This is called whenever an image we care about notifies the
// GlobalImageObserver.
nsresult Notify(imgIRequest*, int32_t aType, const nsIntRect* aData);
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 {
@ -161,9 +165,6 @@ class ImageLoader final : public imgINotificationObserver {
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;
@ -172,40 +173,6 @@ class ImageLoader final : public imgINotificationObserver {
// 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

View File

@ -115,6 +115,8 @@ enum class CallerType : uint32_t;
class Element;
class Document;
class ImageTracker;
} // namespace dom
namespace ipc {
@ -175,6 +177,7 @@ 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;

View File

@ -390,12 +390,14 @@ inline StyleLoadData& StyleCssUrl::LoadData() const {
inline nsIURI* StyleCssUrl::GetURI() const {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
auto& loadData = LoadData();
if (!loadData.tried_to_resolve) {
loadData.tried_to_resolve = true;
NS_NewURI(getter_AddRefs(loadData.resolved), SpecifiedSerialization(),
nullptr, ExtraData().BaseURI());
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();
}
return loadData.resolved.get();
return loadData.resolved_uri;
}
inline nsDependentCSubstring StyleComputedUrl::SpecifiedSerialization() const {
@ -427,6 +429,15 @@ 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;

View File

@ -625,11 +625,6 @@ 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()) {
@ -669,7 +664,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:
@ -678,11 +673,13 @@ static void CollectImageURLsForProperty(nsCSSPropertyID aProp,
case eCSSProperty_mask_clip:
AddImageURLs(aStyle.StyleSVGReset()->mMask, aURLs);
break;
case eCSSProperty_list_style_image:
if (nsStyleImageRequest* image = aStyle.StyleList()->mListStyleImage) {
AddImageURL(*image, aURLs);
case eCSSProperty_list_style_image: {
const auto& image = aStyle.StyleList()->mListStyleImage;
if (image.IsUrl()) {
AddImageURL(image.AsUrl(), aURLs);
}
break;
}
case eCSSProperty_border_image_source:
AddImageURL(aStyle.StyleBorder()->mBorderImageSource, aURLs);
break;

View File

@ -35,6 +35,7 @@
#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"
@ -68,19 +69,6 @@ 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();
@ -95,11 +83,7 @@ bool StyleCssUrlData::operator==(const StyleCssUrlData& aOther) const {
return serialization == aOther.serialization;
}
StyleLoadData::~StyleLoadData() {
if (load_id != 0) {
css::ImageLoader::DeregisterCSSImageFromAllLoaders(*this);
}
}
StyleLoadData::~StyleLoadData() { Gecko_LoadData_Drop(this); }
already_AddRefed<nsIURI> StyleComputedUrl::ResolveLocalRef(nsIURI* aURI) const {
nsCOMPtr<nsIURI> result = GetURI();
@ -122,56 +106,127 @@ already_AddRefed<nsIURI> StyleComputedUrl::ResolveLocalRef(
return ResolveLocalRef(aContent->GetBaseURI());
}
already_AddRefed<imgRequestProxy> StyleComputedUrl::LoadImage(
Document& aDocument) {
void StyleComputedUrl::ResolveImage(Document& aDocument,
const StyleComputedUrl* aOldImage) {
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 nullptr;
return;
}
if (NS_SUCCEEDED(imageURI->EqualsExceptRef(docURI, &isEqualExceptRef)) &&
isEqualExceptRef) {
// Prevent loading an internal resource.
return nullptr;
return;
}
}
static uint64_t sNextLoadID = 1;
MOZ_ASSERT(NS_IsMainThread());
StyleLoadData& data = LoadData();
if (data.load_id == 0) {
data.load_id = sNextLoadID++;
// 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, and same for mSharedCount in the image loader and so on.
const bool reuseProxy = nsContentUtils::IsChromeDoc(&aDocument) &&
aOldImage && aOldImage->IsImageResolved() &&
*this == *aOldImage;
RefPtr<imgRequestProxy> request;
if (reuseProxy) {
request = aOldImage->LoadData().resolved_image;
if (request) {
css::ImageLoader::NoteSharedLoad(request);
}
} 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) {
return nullptr;
return;
}
if (!isPrint) {
return do_AddRef(request);
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;
}
RefPtr<imgRequestProxy> ret;
request->GetStaticRequest(&aDocument, getter_AddRefs(ret));
return ret.forget();
NS_IMETHOD Run() final {
MOZ_ASSERT(NS_IsMainThread());
css::ImageLoader::UnloadImage(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);
}
// --------------------
@ -562,6 +617,7 @@ 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);
@ -574,9 +630,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);
@ -586,9 +642,12 @@ void nsStyleList::TriggerImageLoads(Document& aDocument,
const nsStyleList* aOldStyle) {
MOZ_ASSERT(NS_IsMainThread());
if (mListStyleImage && !mListStyleImage->IsResolved()) {
mListStyleImage->Resolve(
aDocument, aOldStyle ? aOldStyle->mListStyleImage.get() : nullptr);
if (mListStyleImage.IsUrl() && !mListStyleImage.AsUrl().IsImageResolved()) {
auto* oldUrl = aOldStyle && aOldStyle->mListStyleImage.IsUrl()
? &aOldStyle->mListStyleImage.AsUrl()
: nullptr;
const_cast<StyleComputedImageUrl&>(mListStyleImage.AsUrl())
.ResolveImage(aDocument, oldUrl);
}
}
@ -624,7 +683,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 (!DefinitelyEqualImages(mListStyleImage, aNewData.mListStyleImage)) {
if (mListStyleImage != aNewData.mListStyleImage) {
return NS_STYLE_HINT_REFLOW;
}
if (mImageRegion != aNewData.mImageRegion) {
@ -639,11 +698,11 @@ nsChangeHint nsStyleList::CalcDifference(
}
already_AddRefed<nsIURI> nsStyleList::GetListStyleImageURI() const {
if (!mListStyleImage) {
if (!mListStyleImage.IsUrl()) {
return nullptr;
}
nsCOMPtr<nsIURI> uri = mListStyleImage->GetImageURI();
nsCOMPtr<nsIURI> uri = mListStyleImage.AsUrl().GetURI();
return uri.forget();
}
@ -1522,154 +1581,6 @@ 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
//
@ -1720,8 +1631,7 @@ imgIContainer* CachedBorderImageData::GetSubImage(uint8_t aIndex) {
// nsStyleImage
//
nsStyleImage::nsStyleImage()
: mType(eStyleImageType_Null), mImage(nullptr), mCropRect(nullptr) {
nsStyleImage::nsStyleImage() : mCropRect(nullptr), mType(eStyleImageType_Null) {
MOZ_COUNT_CTOR(nsStyleImage);
}
@ -1733,7 +1643,7 @@ nsStyleImage::~nsStyleImage() {
}
nsStyleImage::nsStyleImage(const nsStyleImage& aOther)
: mType(eStyleImageType_Null), mCropRect(nullptr) {
: mCropRect(nullptr), mType(eStyleImageType_Null) {
// We need our own copy constructor because we don't want
// to copy the reference count
MOZ_COUNT_CTOR(nsStyleImage);
@ -1752,7 +1662,7 @@ void nsStyleImage::DoCopy(const nsStyleImage& aOther) {
SetNull();
if (aOther.mType == eStyleImageType_Image) {
SetImageRequest(do_AddRef(aOther.mImage));
SetImageUrl(aOther.mImage);
} else if (aOther.mType == eStyleImageType_Gradient) {
SetGradientData(MakeUnique<StyleGradient>(*aOther.mGradient));
} else if (aOther.mType == eStyleImageType_Element) {
@ -1771,7 +1681,7 @@ void nsStyleImage::SetNull() {
delete mGradient;
mGradient = nullptr;
} else if (mType == eStyleImageType_Image) {
NS_RELEASE(mImage);
mImage.~StyleComputedImageUrl();
} else if (mType == eStyleImageType_Element) {
NS_RELEASE(mElementId);
}
@ -1780,18 +1690,14 @@ void nsStyleImage::SetNull() {
mCropRect = nullptr;
}
void nsStyleImage::SetImageRequest(
already_AddRefed<nsStyleImageRequest> aImage) {
RefPtr<nsStyleImageRequest> image = aImage;
void nsStyleImage::SetImageUrl(const StyleComputedImageUrl& aImage) {
if (mType != eStyleImageType_Null) {
SetNull();
}
if (image) {
mImage = image.forget().take();
mType = eStyleImageType_Image;
}
new (&mImage) StyleComputedImageUrl(aImage);
mType = eStyleImageType_Image;
if (mCachedBIData) {
mCachedBIData->PurgeCachedImages();
}
@ -1837,22 +1743,6 @@ 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,
@ -2009,7 +1899,7 @@ bool nsStyleImage::operator==(const nsStyleImage& aOther) const {
}
if (mType == eStyleImageType_Image) {
return DefinitelyEqualImages(mImage, aOther.mImage);
return mImage == aOther.mImage;
}
if (mType == eStyleImageType_Gradient) {
@ -2046,12 +1936,12 @@ already_AddRefed<nsIURI> nsStyleImage::GetImageURI() const {
return nullptr;
}
nsCOMPtr<nsIURI> uri = mImage->GetImageURI();
nsCOMPtr<nsIURI> uri = mImage.GetURI();
return uri.forget();
}
const StyleComputedImageUrl* nsStyleImage::GetURLValue() const {
return mType == eStyleImageType_Image ? &mImage->GetImageValue() : nullptr;
return mType == eStyleImageType_Image ? &mImage : nullptr;
}
// --------------------
@ -3253,6 +3143,35 @@ 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
//
@ -3501,8 +3420,8 @@ LogicalSide nsStyleText::TextEmphasisSide(WritingMode aWM) const {
// nsStyleUI
//
nsCursorImage::nsCursorImage()
: mHaveHotspot(false), mHotspotX(0.0f), mHotspotY(0.0f) {}
nsCursorImage::nsCursorImage(const StyleComputedImageUrl& aImage)
: mHaveHotspot(false), mHotspotX(0.0f), mHotspotY(0.0f), mImage(aImage) {}
nsCursorImage::nsCursorImage(const nsCursorImage& aOther)
: mHaveHotspot(aOther.mHaveHotspot),
@ -3528,8 +3447,7 @@ 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 &&
DefinitelyEqualImages(mImage, aOther.mImage);
mHotspotY == aOther.mHotspotY && mImage == aOther.mImage;
}
nsStyleUI::nsStyleUI(const Document& aDocument)
@ -3564,13 +3482,13 @@ void nsStyleUI::TriggerImageLoads(Document& aDocument,
for (size_t i = 0; i < mCursorImages.Length(); ++i) {
nsCursorImage& cursor = mCursorImages[i];
if (cursor.mImage && !cursor.mImage->IsResolved()) {
if (!cursor.mImage.IsImageResolved()) {
const nsCursorImage* oldCursor =
(aOldStyle && aOldStyle->mCursorImages.Length() > i)
? &aOldStyle->mCursorImages[i]
: nullptr;
cursor.mImage->Resolve(aDocument,
oldCursor ? oldCursor->mImage.get() : nullptr);
cursor.mImage.ResolveImage(aDocument,
oldCursor ? &oldCursor->mImage : nullptr);
}
}
}

View File

@ -133,96 +133,6 @@ 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,
@ -268,36 +178,34 @@ struct nsStyleImage {
nsStyleImage& operator=(const nsStyleImage& aOther);
void SetNull();
void SetImageRequest(already_AddRefed<nsStyleImageRequest> aImage);
void SetImageUrl(const mozilla::StyleComputedImageUrl&);
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) {
MOZ_ASSERT(mType != eStyleImageType_Image || mImage);
if (mType == eStyleImageType_Image && !mImage->IsResolved()) {
const nsStyleImageRequest* oldRequest =
if (mType == eStyleImageType_Image && !mImage.IsImageResolved()) {
const auto* oldRequest =
(aOldImage && aOldImage->GetType() == eStyleImageType_Image)
? aOldImage->ImageRequest()
? &aOldImage->ImageUrl()
: nullptr;
mImage->Resolve(aDocument, oldRequest);
mImage.ResolveImage(aDocument, oldRequest);
}
}
nsStyleImageType GetType() const { return mType; }
nsStyleImageRequest* ImageRequest() const {
const mozilla::StyleComputedImageUrl& ImageUrl() const {
MOZ_ASSERT(mType == eStyleImageType_Image, "Data is not an image!");
MOZ_ASSERT(mImage);
return mImage;
}
imgRequestProxy* GetImageData() const { return ImageRequest()->get(); }
imgRequestProxy* GetImageData() const { return ImageUrl().GetImage(); }
const mozilla::StyleGradient& GetGradient() const {
NS_ASSERTION(mType == eStyleImageType_Gradient, "Data is not a gradient!");
return *mGradient;
}
bool IsResolved() const {
return mType != eStyleImageType_Image || ImageRequest()->IsResolved();
return mType != eStyleImageType_Image || ImageUrl().IsImageResolved();
}
const nsAtom* GetElementId() const {
NS_ASSERTION(mType == eStyleImageType_Element, "Data is not an element!");
@ -391,15 +299,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 {
nsStyleImageRequest* mImage;
mozilla::StyleComputedImageUrl mImage;
mozilla::StyleGradient* mGradient;
nsAtom* mElementId;
};
// This is _currently_ used only in conjunction with eStyleImageType_Image.
mozilla::UniquePtr<CropRect> mCropRect;
};
struct nsStyleImageLayers {
@ -920,6 +828,10 @@ 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;
@ -927,7 +839,8 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList {
const nsStyleDisplay& aOldDisplay) const;
imgRequestProxy* GetListStyleImage() const {
return mListStyleImage ? mListStyleImage->get() : nullptr;
return mListStyleImage.IsUrl() ? mListStyleImage.AsUrl().GetImage()
: nullptr;
}
nsRect GetImageRegion() const {
@ -940,18 +853,15 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList {
already_AddRefed<nsIURI> GetListStyleImageURI() const;
uint8_t mListStylePosition;
RefPtr<nsStyleImageRequest> mListStyleImage;
mozilla::CounterStylePtr mCounterStyle;
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
mozilla::StyleImageUrlOrNone mListStyleImage;
// the rect to use within an image.
mozilla::StyleClipRectOrAuto mImageRegion;
// true in an <ol reversed> scope.
mozilla::StyleMozListReversed mMozListReversed;
};
struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePosition {
@ -1919,7 +1829,9 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleContent {
explicit nsStyleContent(const mozilla::dom::Document&);
nsStyleContent(const nsStyleContent& aContent);
~nsStyleContent();
static constexpr bool kHasTriggerImageLoads = false;
void TriggerImageLoads(mozilla::dom::Document&, const nsStyleContent*);
static constexpr bool kHasTriggerImageLoads = true;
size_t ContentCount() const {
return mContent.IsItems() ? mContent.AsItems().Length() : 0;
@ -1959,10 +1871,10 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUIReset {
struct nsCursorImage {
bool mHaveHotspot;
float mHotspotX, mHotspotY;
RefPtr<nsStyleImageRequest> mImage;
mozilla::StyleComputedImageUrl mImage;
nsCursorImage();
nsCursorImage(const nsCursorImage& aOther);
explicit nsCursorImage(const mozilla::StyleComputedImageUrl&);
nsCursorImage(const nsCursorImage&);
nsCursorImage& operator=(const nsCursorImage& aOther);
@ -1971,7 +1883,7 @@ struct nsCursorImage {
return !(*this == aOther);
}
imgRequestProxy* GetImage() const { return mImage->get(); }
imgRequestProxy* GetImage() const { return mImage.GetImage(); }
};
struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUI {

View File

@ -876,17 +876,16 @@ void SVGMaskObserverList::ResolveImage(uint32_t aIndex) {
const nsStyleSVGReset* svgReset = mFrame->StyleSVGReset();
MOZ_ASSERT(aIndex < svgReset->mMask.mImageCount);
nsStyleImage& image =
auto& 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);
mozilla::css::ImageLoader* imageLoader =
mFrame->PresContext()->Document()->StyleImageLoader();
Document* doc = mFrame->PresContext()->Document();
if (imgRequestProxy* req = image.GetImageData()) {
imageLoader->AssociateRequestToFrame(req, mFrame, 0);
doc->StyleImageLoader()->AssociateRequestToFrame(req, mFrame, 0);
}
}
}

View File

@ -15,7 +15,6 @@ 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;
@ -63,7 +62,7 @@ impl nsStyleImage {
match self.mType {
nsStyleImageType::eStyleImageType_Null => None,
nsStyleImageType::eStyleImageType_Image => {
let url = self.get_image_url();
let url = self.__bindgen_anon_1.mImage.as_ref().clone();
if self.mCropRect.mPtr.is_null() {
Some(GenericImage::Url(url))
} else {
@ -88,13 +87,6 @@ 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 {

View File

@ -6,8 +6,6 @@
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};
@ -150,31 +148,52 @@ struct LoadDataKey(*const LoadDataSource);
unsafe impl Sync for LoadDataKey {}
unsafe impl Send for LoadDataKey {}
/// The load data for a given URL. This is mutable from C++, for now at least.
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.
#[repr(C)]
#[derive(Debug)]
pub struct LoadData {
resolved: RefPtr<structs::nsIURI>,
load_id: u64,
tried_to_resolve: bool,
/// 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,
}
impl Drop for LoadData {
fn drop(&mut self) {
if self.load_id != 0 {
unsafe {
bindings::Gecko_LoadData_DeregisterLoad(self);
}
}
unsafe { bindings::Gecko_LoadData_Drop(self) }
}
}
impl Default for LoadData {
fn default() -> Self {
Self {
resolved: RefPtr::null(),
load_id: 0,
tried_to_resolve: false,
resolved_image: std::ptr::null_mut(),
resolved_uri: std::ptr::null_mut(),
flags: LoadDataFlags::empty(),
}
}
}
@ -342,13 +361,6 @@ 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

View File

@ -25,14 +25,9 @@ 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;
@ -53,7 +48,6 @@ 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 {
@ -2108,43 +2102,7 @@ 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-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))
}
}
<%self:impl_trait style_struct_name="List" skip_longhands="list-style-type">
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;
@ -2433,14 +2391,11 @@ clip-path
pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) {
self.gecko.mCursor = v.keyword;
unsafe {
Gecko_SetCursorArrayLength(&mut *self.gecko, v.images.len());
bindings::Gecko_SetCursorArrayCapacity(&mut *self.gecko, v.images.len());
}
for i in 0..v.images.len() {
unsafe {
Gecko_SetCursorImageValue(
&mut self.gecko.mCursorImages[i],
&v.images[i].url
);
bindings::Gecko_AppendCursorImage(&mut *self.gecko, &v.images[i].url);
}
match v.images[i].hotspot {
@ -2473,10 +2428,7 @@ clip-path
let keyword = self.gecko.mCursor;
let images = self.gecko.mCursorImages.iter().map(|gecko_cursor_image| {
let url = unsafe {
let gecko_image_request = gecko_cursor_image.mImage.mRawPtr.as_ref().unwrap();
ComputedImageUrl::from_image_request(&gecko_image_request)
};
let url = gecko_cursor_image.mImage.clone();
let hotspot =
if gecko_cursor_image.mHaveHotspot {

View File

@ -170,6 +170,7 @@ include = [
"ComputedUrl",
"ComputedImageUrl",
"UrlOrNone",
"ImageUrlOrNone",
"Filter",
"Gradient",
"GridTemplateAreas",
@ -206,6 +207,7 @@ renaming_overrides_prefixing = true
"nscolor" = "nscolor"
"nsAtom" = "nsAtom"
"nsIURI" = "nsIURI"
"imgRequestProxy" = "imgRequestProxy"
"nsCompatibility" = "nsCompatibility"
"SharedFontList" = "SharedFontList"
"nsSimpleContentList" = "nsSimpleContentList"
@ -651,7 +653,11 @@ renaming_overrides_prefixing = true
inline StyleCorsMode CorsMode() const;
already_AddRefed<nsIURI> ResolveLocalRef(nsIURI* aBase) 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" = """