Bug 1288302 - Part 5: Make nsStyleImage use nsStyleImageRequest. r=bholley

This makes background-image, mask-image and border-image settable
from Servo.

Since imgRequestProxy resolution in nsStyleImages can now happen later than
at computed value setting time, and that resolution can fail,
nsStyleImage::GetImageData() might now return null.  So all of the users of
nsStyleImage now null check its result.

MozReview-Commit-ID: FMRUrC3SfOs
This commit is contained in:
Cameron McCormack 2016-11-02 16:58:32 +08:00
Родитель 642cdb8e14
Коммит 32c930ba08
7 изменённых файлов: 152 добавлений и 133 удалений

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

@ -667,10 +667,6 @@ nsCSSRendering::PaintBorder(nsPresContext* aPresContext,
}
nsStyleBorder newStyleBorder(*styleBorder);
// We could do something fancy to avoid the TrackImage/UntrackImage
// work, but it doesn't seem worth it. (We need to call TrackImage
// since we're not going through nsRuleNode::ComputeBorderData.)
newStyleBorder.TrackImage(aPresContext->Document()->ImageTracker());
NS_FOR_CSS_SIDES(side) {
nscolor color = aStyleContext->GetVisitedDependentColor(
@ -682,11 +678,6 @@ nsCSSRendering::PaintBorder(nsPresContext* aPresContext,
aDirtyRect, aBorderArea, newStyleBorder,
aStyleContext, aFlags, aSkipSides);
// We could do something fancy to avoid the TrackImage/UntrackImage
// work, but it doesn't seem worth it. (We need to call UntrackImage
// since we're not going through nsStyleBorder::Destroy.)
newStyleBorder.UntrackImage(aPresContext->Document()->ImageTracker());
return result;
}
@ -5032,8 +5023,13 @@ ShouldTreatAsCompleteDueToSyncDecode(const nsStyleImage* aImage,
return false;
}
imgRequestProxy* req = aImage->GetImageData();
if (!req) {
return false;
}
uint32_t status = 0;
if (NS_FAILED(aImage->GetImageData()->GetImageStatus(&status))) {
if (NS_FAILED(req->GetImageStatus(&status))) {
return false;
}
@ -5041,7 +5037,7 @@ ShouldTreatAsCompleteDueToSyncDecode(const nsStyleImage* aImage,
// The image is "complete" since it's a corrupt image. If we created an
// imgIContainer at all, return true.
nsCOMPtr<imgIContainer> image;
aImage->GetImageData()->GetImage(getter_AddRefs(image));
req->GetImage(getter_AddRefs(image));
return bool(image);
}
@ -5078,8 +5074,9 @@ nsImageRenderer::PrepareImage()
}
switch (mType) {
case eStyleImageType_Image:
{
case eStyleImageType_Image: {
MOZ_ASSERT(mImage->GetImageData(),
"must have image data, since we checked IsEmpty above");
nsCOMPtr<imgIContainer> srcImage;
DebugOnly<nsresult> rv =
mImage->GetImageData()->GetImage(getter_AddRefs(srcImage));

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

@ -2871,7 +2871,9 @@ nsDisplayBackgroundImage::ShouldCreateOwnLayer(nsDisplayListBuilder* aBuilder,
if (image->GetType() == eStyleImageType_Image) {
imgIRequest* imgreq = image->GetImageData();
nsCOMPtr<imgIContainer> image;
if (NS_SUCCEEDED(imgreq->GetImage(getter_AddRefs(image))) && image) {
if (imgreq &&
NS_SUCCEEDED(imgreq->GetImage(getter_AddRefs(image))) &&
image) {
bool animated = false;
if (NS_SUCCEEDED(image->GetAnimated(&animated)) && animated) {
return WHENEVER_POSSIBLE;

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

@ -792,8 +792,9 @@ AddAndRemoveImageAssociations(nsFrame* aFrame,
continue;
}
imageLoader->DisassociateRequestFromFrame(oldImage.GetImageData(),
aFrame);
if (imgRequestProxy* req = oldImage.GetImageData()) {
imageLoader->DisassociateRequestFromFrame(req, aFrame);
}
}
}
}
@ -808,7 +809,9 @@ AddAndRemoveImageAssociations(nsFrame* aFrame,
continue;
}
imageLoader->AssociateRequestToFrame(newImage.GetImageData(), aFrame);
if (imgRequestProxy* req = newImage.GetImageData()) {
imageLoader->AssociateRequestToFrame(req, aFrame);
}
}
}
}
@ -4300,7 +4303,11 @@ nsIFrame::AssociateImage(const nsStyleImage& aImage, nsPresContext* aPresContext
return;
}
imgIRequest *req = aImage.GetImageData();
imgRequestProxy* req = aImage.GetImageData();
if (!req) {
return;
}
mozilla::css::ImageLoader* loader =
aPresContext->Document()->StyleImageLoader();

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

@ -2082,7 +2082,15 @@ nsComputedDOMStyle::SetValueToStyleImage(const nsStyleImage& aStyleImage,
switch (aStyleImage.GetType()) {
case eStyleImageType_Image:
{
imgIRequest *req = aStyleImage.GetImageData();
imgIRequest* req = aStyleImage.GetImageData();
if (!req) {
// XXXheycam If we had some problem resolving the imgRequestProxy,
// maybe we should just use the URL stored in the nsStyleImage's
// mImageValue?
aValue->SetIdent(eCSSKeyword_none);
break;
}
nsCOMPtr<nsIURI> uri;
req->GetURI(getter_AddRefs(uri));

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

@ -134,6 +134,26 @@ SetImageRequest(function<void(imgRequestProxy*)> aCallback,
aCallback(req);
}
static void
SetStyleImageRequest(function<void(nsStyleImageRequest*)> aCallback,
nsPresContext* aPresContext,
const nsCSSValue& aValue,
nsStyleImageRequest::Mode aModeFlags =
nsStyleImageRequest::Mode::Track |
nsStyleImageRequest::Mode::Lock)
{
SetImageRequest([&](imgRequestProxy* aProxy) {
RefPtr<nsStyleImageRequest> request;
if (aProxy) {
css::ImageValue* imageValue = aValue.GetImageStructValue();
ImageTracker* imageTracker = aPresContext->Document()->ImageTracker();
request =
new nsStyleImageRequest(aModeFlags, aProxy, imageValue, imageTracker);
}
aCallback(request);
}, aPresContext, aValue);
}
template<typename ReferenceBox>
static void
SetStyleShapeSourceToCSSValue(StyleShapeSource<ReferenceBox>* aShapeSource,
@ -1264,8 +1284,8 @@ static void SetStyleImageToImageRect(nsStyleContext* aStyleContext,
// <uri>
if (arr->Item(1).GetUnit() == eCSSUnit_Image) {
SetImageRequest([&](imgRequestProxy* req) {
aResult.SetImageData(req);
SetStyleImageRequest([&](nsStyleImageRequest* req) {
aResult.SetImageRequest(do_AddRef(req));
}, aStyleContext->PresContext(), arr->Item(1));
} else {
NS_WARNING("nsCSSValue::Image::Image() failed?");
@ -1300,8 +1320,8 @@ static void SetStyleImage(nsStyleContext* aStyleContext,
switch (aValue.GetUnit()) {
case eCSSUnit_Image:
SetImageRequest([&](imgRequestProxy* req) {
aResult.SetImageData(req);
SetStyleImageRequest([&](nsStyleImageRequest* req) {
aResult.SetImageRequest(do_AddRef(req));
}, aStyleContext->PresContext(), aValue);
break;
case eCSSUnit_Function:
@ -7327,9 +7347,6 @@ nsRuleNode::ComputeBackgroundData(void* aStartStruct,
FillAllBackgroundLists(bg->mImage, maxItemCount);
}
// Now that the dust has settled, register the images with the document
bg->mImage.TrackImages(aContext->PresContext()->Document()->ImageTracker());
COMPUTE_END_RESET(Background, bg)
}
@ -7716,8 +7733,6 @@ nsRuleNode::ComputeBorderData(void* aStartStruct,
parentBorder->mBorderImageRepeatV,
NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH);
border->TrackImage(aContext->PresContext()->Document()->ImageTracker());
COMPUTE_END_RESET(Border, border)
}
@ -10046,8 +10061,6 @@ nsRuleNode::ComputeSVGResetData(void* aStartStruct,
}
#endif
svgReset->mMask.TrackImages(aContext->PresContext()->Document()->ImageTracker());
COMPUTE_END_RESET(SVGReset, svgReset)
}

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

@ -449,6 +449,15 @@ nsStyleBorder::~nsStyleBorder()
}
}
void
nsStyleBorder::FinishStyle(nsPresContext* aPresContext)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPresContext->StyleSet()->IsServo());
mBorderImageSource.ResolveImage(aPresContext);
}
nsMargin
nsStyleBorder::GetImageOutset() const
{
@ -479,8 +488,6 @@ nsStyleBorder::GetImageOutset() const
void
nsStyleBorder::Destroy(nsPresContext* aContext)
{
UntrackImage(aContext->Document()->ImageTracker());
this->~nsStyleBorder();
aContext->PresShell()->
FreeByObjectID(eArenaObjectID_nsStyleBorder, this);
@ -1184,13 +1191,20 @@ nsStyleSVGReset::nsStyleSVGReset(const nsStyleSVGReset& aSource)
void
nsStyleSVGReset::Destroy(nsPresContext* aContext)
{
mMask.UntrackImages(aContext->Document()->ImageTracker());
this->~nsStyleSVGReset();
aContext->PresShell()->
FreeByObjectID(mozilla::eArenaObjectID_nsStyleSVGReset, this);
}
void
nsStyleSVGReset::FinishStyle(nsPresContext* aPresContext)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPresContext->StyleSet()->IsServo());
mMask.ResolveImages(aPresContext);
}
nsChangeHint
nsStyleSVGReset::CalcDifference(const nsStyleSVGReset& aNewData) const
{
@ -2096,9 +2110,6 @@ CachedBorderImageData::GetSubImage(uint8_t aIndex)
nsStyleImage::nsStyleImage()
: mType(eStyleImageType_Null)
, mCropRect(nullptr)
#ifdef DEBUG
, mImageTracked(false)
#endif
{
MOZ_COUNT_CTOR(nsStyleImage);
}
@ -2114,9 +2125,6 @@ nsStyleImage::~nsStyleImage()
nsStyleImage::nsStyleImage(const nsStyleImage& aOther)
: mType(eStyleImageType_Null)
, mCropRect(nullptr)
#ifdef DEBUG
, mImageTracked(false)
#endif
{
// We need our own copy constructor because we don't want
// to copy the reference count
@ -2140,7 +2148,7 @@ nsStyleImage::DoCopy(const nsStyleImage& aOther)
SetNull();
if (aOther.mType == eStyleImageType_Image) {
SetImageData(aOther.mImage);
SetImageRequest(do_AddRef(aOther.mImage));
} else if (aOther.mType == eStyleImageType_Gradient) {
SetGradientData(aOther.mGradient);
} else if (aOther.mType == eStyleImageType_Element) {
@ -2157,9 +2165,6 @@ nsStyleImage::DoCopy(const nsStyleImage& aOther)
void
nsStyleImage::SetNull()
{
MOZ_ASSERT(!mImageTracked,
"Calling SetNull() with image tracked!");
if (mType == eStyleImageType_Gradient) {
mGradient->Release();
} else if (mType == eStyleImageType_Image) {
@ -2173,19 +2178,16 @@ nsStyleImage::SetNull()
}
void
nsStyleImage::SetImageData(imgRequestProxy* aImage)
nsStyleImage::SetImageRequest(already_AddRefed<nsStyleImageRequest> aImage)
{
MOZ_ASSERT(!mImageTracked,
"Setting a new image without untracking the old one!");
NS_IF_ADDREF(aImage);
RefPtr<nsStyleImageRequest> image = aImage;
if (mType != eStyleImageType_Null) {
SetNull();
}
if (aImage) {
mImage = aImage;
if (image) {
mImage = image.forget().take();
mType = eStyleImageType_Image;
}
if (mCachedBIData) {
@ -2193,38 +2195,6 @@ nsStyleImage::SetImageData(imgRequestProxy* aImage)
}
}
void
nsStyleImage::TrackImage(ImageTracker* aImageTracker)
{
// Sanity
MOZ_ASSERT(!mImageTracked, "Already tracking image!");
MOZ_ASSERT(mType == eStyleImageType_Image,
"Can't track image when there isn't one!");
aImageTracker->Add(mImage);
// Mark state
#ifdef DEBUG
mImageTracked = true;
#endif
}
void
nsStyleImage::UntrackImage(ImageTracker* aImageTracker)
{
// Sanity
MOZ_ASSERT(mImageTracked, "Image not tracked!");
MOZ_ASSERT(mType == eStyleImageType_Image,
"Can't untrack image when there isn't one!");
aImageTracker->Remove(mImage);
// Mark state
#ifdef DEBUG
mImageTracked = false;
#endif
}
void
nsStyleImage::SetGradientData(nsStyleGradient* aGradient)
{
@ -2289,8 +2259,13 @@ nsStyleImage::ComputeActualCropRect(nsIntRect& aActualCropRect,
return false;
}
imgRequestProxy* req = GetImageData();
if (!req) {
return false;
}
nsCOMPtr<imgIContainer> imageContainer;
mImage->GetImage(getter_AddRefs(imageContainer));
req->GetImage(getter_AddRefs(imageContainer));
if (!imageContainer) {
return false;
}
@ -2322,7 +2297,11 @@ nsresult
nsStyleImage::StartDecoding() const
{
if (mType == eStyleImageType_Image) {
return mImage->StartDecoding();
imgRequestProxy* req = GetImageData();
if (!req) {
return NS_ERROR_FAILURE;
}
return req->StartDecoding();
}
return NS_OK;
}
@ -2343,9 +2322,10 @@ nsStyleImage::IsOpaque() const
}
MOZ_ASSERT(mType == eStyleImageType_Image, "unexpected image type");
MOZ_ASSERT(GetImageData(), "should've returned earlier above");
nsCOMPtr<imgIContainer> imageContainer;
mImage->GetImage(getter_AddRefs(imageContainer));
GetImageData()->GetImage(getter_AddRefs(imageContainer));
MOZ_ASSERT(imageContainer, "IsComplete() said image container is ready");
// Check if the crop region of the image is opaque.
@ -2374,10 +2354,13 @@ nsStyleImage::IsComplete() const
case eStyleImageType_Gradient:
case eStyleImageType_Element:
return true;
case eStyleImageType_Image:
{
case eStyleImageType_Image: {
imgRequestProxy* req = GetImageData();
if (!req) {
return false;
}
uint32_t status = imgIRequest::STATUS_ERROR;
return NS_SUCCEEDED(mImage->GetImageStatus(&status)) &&
return NS_SUCCEEDED(req->GetImageStatus(&status)) &&
(status & imgIRequest::STATUS_SIZE_AVAILABLE) &&
(status & imgIRequest::STATUS_FRAME_COMPLETE);
}
@ -2396,10 +2379,13 @@ nsStyleImage::IsLoaded() const
case eStyleImageType_Gradient:
case eStyleImageType_Element:
return true;
case eStyleImageType_Image:
{
case eStyleImageType_Image: {
imgRequestProxy* req = GetImageData();
if (!req) {
return false;
}
uint32_t status = imgIRequest::STATUS_ERROR;
return NS_SUCCEEDED(mImage->GetImageStatus(&status)) &&
return NS_SUCCEEDED(req->GetImageStatus(&status)) &&
!(status & imgIRequest::STATUS_ERROR) &&
(status & imgIRequest::STATUS_LOAD_COMPLETE);
}
@ -2428,7 +2414,7 @@ nsStyleImage::operator==(const nsStyleImage& aOther) const
}
if (mType == eStyleImageType_Image) {
return EqualImages(mImage, aOther.mImage);
return DefinitelyEqualImages(mImage, aOther.mImage);
}
if (mType == eStyleImageType_Gradient) {
@ -2708,7 +2694,9 @@ nsStyleImageLayers::Size::DependsOnPositioningAreaSize(const nsStyleImage& aImag
if (type == eStyleImageType_Image) {
nsCOMPtr<imgIContainer> imgContainer;
aImage.GetImageData()->GetImage(getter_AddRefs(imgContainer));
if (imgRequestProxy* req = aImage.GetImageData()) {
req->GetImage(getter_AddRefs(imgContainer));
}
if (imgContainer) {
CSSIntSize imageSize;
nsSize imageRatio;
@ -2913,14 +2901,20 @@ nsStyleBackground::~nsStyleBackground()
void
nsStyleBackground::Destroy(nsPresContext* aContext)
{
// Untrack all the images stored in our layers
mImage.UntrackImages(aContext->Document()->ImageTracker());
this->~nsStyleBackground();
aContext->PresShell()->
FreeByObjectID(eArenaObjectID_nsStyleBackground, this);
}
void
nsStyleBackground::FinishStyle(nsPresContext* aPresContext)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPresContext->StyleSet()->IsServo());
mImage.ResolveImages(aPresContext);
}
nsChangeHint
nsStyleBackground::CalcDifference(const nsStyleBackground& aNewData) const
{

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

@ -417,23 +417,29 @@ struct nsStyleImage
nsStyleImage& operator=(const nsStyleImage& aOther);
void SetNull();
void SetImageData(imgRequestProxy* aImage);
void TrackImage(mozilla::dom::ImageTracker* aImageTracker);
void UntrackImage(mozilla::dom::ImageTracker* aImageTracker);
void SetImageRequest(already_AddRefed<nsStyleImageRequest> aImage);
void SetGradientData(nsStyleGradient* aGradient);
void SetElementId(const char16_t* aElementId);
void SetCropRect(mozilla::UniquePtr<nsStyleSides> aCropRect);
void ResolveImage(nsPresContext* aContext) {
MOZ_ASSERT(mType != eStyleImageType_Image || mImage);
if (mType == eStyleImageType_Image && !mImage->IsResolved()) {
mImage->Resolve(aContext);
}
}
nsStyleImageType GetType() const {
return mType;
}
imgRequestProxy* GetImageData() const {
nsStyleImageRequest* GetImageRequest() const {
MOZ_ASSERT(mType == eStyleImageType_Image, "Data is not an image!");
MOZ_ASSERT(mImage);
MOZ_ASSERT(mImageTracked,
"Should be tracking any image we're going to use!");
return mImage;
}
imgRequestProxy* GetImageData() const {
return GetImageRequest()->get();
}
nsStyleGradient* GetGradientData() const {
NS_ASSERTION(mType == eStyleImageType_Gradient, "Data is not a gradient!");
return mGradient;
@ -526,16 +532,13 @@ private:
nsStyleImageType mType;
union {
imgRequestProxy* mImage;
nsStyleImageRequest* mImage;
nsStyleGradient* mGradient;
char16_t* mElementId;
};
// This is _currently_ used only in conjunction with eStyleImageType_Image.
mozilla::UniquePtr<nsStyleSides> mCropRect;
#ifdef DEBUG
bool mImageTracked;
#endif
};
struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleColor
@ -814,16 +817,9 @@ struct nsStyleImageLayers {
// Initialize mRepeat and mOrigin by specified layer type
void Initialize(LayerType aType);
// Register/unregister images with the document. We do this only
// after the dust has settled in ComputeBackgroundData.
void TrackImages(mozilla::dom::ImageTracker* aImageTracker) {
void ResolveImage(nsPresContext* aContext) {
if (mImage.GetType() == eStyleImageType_Image) {
mImage.TrackImage(aImageTracker);
}
}
void UntrackImages(mozilla::dom::ImageTracker* aImageTracker) {
if (mImage.GetType() == eStyleImageType_Image) {
mImage.UntrackImage(aImageTracker);
mImage.ResolveImage(aContext);
}
}
@ -873,15 +869,11 @@ struct nsStyleImageLayers {
const Layer& BottomLayer() const { return mLayers[mImageCount - 1]; }
void TrackImages(mozilla::dom::ImageTracker* aImageTracker) {
void ResolveImages(nsPresContext* aContext) {
for (uint32_t i = 0; i < mImageCount; ++i) {
mLayers[i].TrackImages(aImageTracker);
mLayers[i].ResolveImage(aContext);
}
}
void UntrackImages(mozilla::dom::ImageTracker* aImageTracker) {
for (uint32_t i = 0; i < mImageCount; ++i)
mLayers[i].UntrackImages(aImageTracker);
}
nsChangeHint CalcDifference(const nsStyleImageLayers& aNewLayers,
nsStyleImageLayers::LayerType aType) const;
@ -903,7 +895,11 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleBackground {
explicit nsStyleBackground(StyleStructContext aContext);
nsStyleBackground(const nsStyleBackground& aOther);
~nsStyleBackground();
void FinishStyle(nsPresContext* aPresContext) {}
// Resolves and tracks the images in mImage. Only called with a Servo-backed
// style system, where those images must be resolved later than the OMT
// nsStyleBackground constructor call.
void FinishStyle(nsPresContext* aPresContext);
void* operator new(size_t sz, nsStyleBackground* aSelf) { return aSelf; }
void* operator new(size_t sz, nsPresContext* aContext) {
@ -1212,7 +1208,11 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleBorder
explicit nsStyleBorder(StyleStructContext aContext);
nsStyleBorder(const nsStyleBorder& aBorder);
~nsStyleBorder();
void FinishStyle(nsPresContext* aPresContext) {}
// Resolves and tracks mBorderImageSource. Only called with a Servo-backed
// style system, where those images must be resolved later than the OMT
// nsStyleBorder constructor call.
void FinishStyle(nsPresContext* aPresContext);
void* operator new(size_t sz, nsStyleBorder* aSelf) { return aSelf; }
void* operator new(size_t sz, nsPresContext* aContext) {
@ -1316,16 +1316,10 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleBorder
return mBorderImageSource.IsLoaded();
}
void TrackImage(mozilla::dom::ImageTracker* aImageTracker)
void ResolveImage(nsPresContext* aContext)
{
if (mBorderImageSource.GetType() == eStyleImageType_Image) {
mBorderImageSource.TrackImage(aImageTracker);
}
}
void UntrackImage(mozilla::dom::ImageTracker* aImageTracker)
{
if (mBorderImageSource.GetType() == eStyleImageType_Image) {
mBorderImageSource.UntrackImage(aImageTracker);
mBorderImageSource.ResolveImage(aContext);
}
}
@ -3768,7 +3762,11 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVGReset
explicit nsStyleSVGReset(StyleStructContext aContext);
nsStyleSVGReset(const nsStyleSVGReset& aSource);
~nsStyleSVGReset();
void FinishStyle(nsPresContext* aPresContext) {}
// Resolves and tracks the images in mMask. Only called with a Servo-backed
// style system, where those images must be resolved later than the OMT
// nsStyleSVGReset constructor call.
void FinishStyle(nsPresContext* aPresContext);
void* operator new(size_t sz, nsStyleSVGReset* aSelf) { return aSelf; }
void* operator new(size_t sz, nsPresContext* aContext) {