Bug 1614198 - Use cbindgen instead of nsStyleImage. r=aosmond

The trickier part is that we represent -moz-image-rect as a Rect() type instead
of image with non-null clip-rect. So we need to add a bit of code to
distinguish "image request types" from other types of images.

But it's not too annoying, and we need to do the same for fancier images like
image-set and such whenever we implement it, so seems nice to get rid of
most explicit usages of nsStyleImage::GetType().

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Emilio Cobos Álvarez 2020-02-11 20:56:20 +00:00
parent 21f524eca1
commit 006e5cca66
26 changed files with 433 additions and 840 deletions

View File

@ -26,8 +26,8 @@ namespace image {
* SUCCESS_NOT_COMPLETE: The image was drawn successfully and completely, but
* it hasn't notified about the sync-decode yet. This can only happen when
* layout pokes at the internal image state beforehand via
* nsStyleImage::StartDecoding. This should probably go away eventually,
* somehow, see bug 1471583.
* StyleImage::StartDecoding. This should probably go away eventually, somehow,
* see bug 1471583.
*
* INCOMPLETE: We successfully drew a frame that was partially decoded. (Note
* that successfully drawing a partially decoded frame may not actually draw any

View File

@ -519,7 +519,7 @@ void nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// Create separate items for each background layer.
const nsStyleImageLayers& layers = bg->StyleBackground()->mImage;
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, layers) {
if (layers.mLayers[i].mImage.IsEmpty()) {
if (layers.mLayers[i].mImage.IsNone()) {
continue;
}
if (layers.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) {

View File

@ -237,7 +237,7 @@ void nsColumnSetFrame::CreateBorderRenderers(
// Assert that we're not drawing a border-image here; if we were, we
// couldn't ignore the ImgDrawResult that PaintBorderWithStyleBorder
// returns.
MOZ_ASSERT(border.mBorderImageSource.GetType() == eStyleImageType_Null);
MOZ_ASSERT(border.mBorderImageSource.IsNone());
gfx::DrawTarget* dt = aCtx ? aCtx->GetDrawTarget() : nullptr;
bool borderIsEmpty = false;

View File

@ -569,7 +569,7 @@ class nsFloatManager::ShapeInfo {
WritingMode aWM,
const nsSize& aContainerSize);
static UniquePtr<ShapeInfo> CreateImageShape(const nsStyleImage& aShapeImage,
static UniquePtr<ShapeInfo> CreateImageShape(const StyleImage& aShapeImage,
float aShapeImageThreshold,
nscoord aShapeMargin,
nsIFrame* const aFrame,
@ -2665,7 +2665,7 @@ nsFloatManager::ShapeInfo::CreatePolygon(const StyleBasicShape& aBasicShape,
}
/* static */ UniquePtr<nsFloatManager::ShapeInfo>
nsFloatManager::ShapeInfo::CreateImageShape(const nsStyleImage& aShapeImage,
nsFloatManager::ShapeInfo::CreateImageShape(const StyleImage& aShapeImage,
float aShapeImageThreshold,
nscoord aShapeMargin,
nsIFrame* const aFrame,
@ -2682,10 +2682,8 @@ nsFloatManager::ShapeInfo::CreateImageShape(const nsStyleImage& aShapeImage,
if (!imageRenderer.PrepareImage()) {
// The image is not ready yet. Boost its loading priority since it will
// affect layout.
if (aShapeImage.GetType() == eStyleImageType_Image) {
if (imgRequestProxy* req = aShapeImage.GetImageData()) {
req->BoostPriority(imgIRequest::CATEGORY_SIZE_QUERY);
}
if (imgRequestProxy* req = aShapeImage.GetImageRequest()) {
req->BoostPriority(imgIRequest::CATEGORY_SIZE_QUERY);
}
return nullptr;
}

View File

@ -923,8 +923,8 @@ static void CompareLayers(
const nsStyleImageLayers* aSecondLayers,
const std::function<void(imgRequestProxy* aReq)>& aCallback) {
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, (*aFirstLayers)) {
const nsStyleImage& image = aFirstLayers->mLayers[i].mImage;
if (image.GetType() != eStyleImageType_Image || !image.IsResolved()) {
const auto& image = aFirstLayers->mLayers[i].mImage;
if (!image.IsImageRequestType() || !image.IsResolved()) {
continue;
}
@ -932,8 +932,8 @@ static void CompareLayers(
// be different with the corresponded one in aSecondLayers
if (!aSecondLayers || i >= aSecondLayers->mImageCount ||
(!aSecondLayers->mLayers[i].mImage.IsResolved() ||
!image.ImageDataEquals(aSecondLayers->mLayers[i].mImage))) {
if (imgRequestProxy* req = image.GetImageData()) {
image.GetImageRequest() != aSecondLayers->mLayers[i].mImage.GetImageRequest())) {
if (imgRequestProxy* req = image.GetImageRequest()) {
aCallback(req);
}
}
@ -5523,12 +5523,8 @@ nsIFrame::ContentOffsets nsFrame::CalcContentOffsetsFromFramePoint(
return OffsetsForSingleFrame(this, aPoint);
}
bool nsIFrame::AssociateImage(const nsStyleImage& aImage) {
if (aImage.GetType() != eStyleImageType_Image) {
return false;
}
imgRequestProxy* req = aImage.GetImageData();
bool nsIFrame::AssociateImage(const StyleImage& aImage) {
imgRequestProxy* req = aImage.GetImageRequest();
if (!req) {
return false;
}
@ -5540,12 +5536,8 @@ bool nsIFrame::AssociateImage(const nsStyleImage& aImage) {
return true;
}
void nsIFrame::DisassociateImage(const nsStyleImage& aImage) {
if (aImage.GetType() != eStyleImageType_Image) {
return;
}
imgRequestProxy* req = aImage.GetImageData();
void nsIFrame::DisassociateImage(const StyleImage& aImage) {
imgRequestProxy* req = aImage.GetImageRequest();
if (!req) {
return;
}

View File

@ -2025,13 +2025,13 @@ class nsIFrame : public nsQueryFrame {
*
* Returns whether the image was in fact associated with the frame.
*/
MOZ_MUST_USE bool AssociateImage(const nsStyleImage&);
MOZ_MUST_USE bool AssociateImage(const mozilla::StyleImage&);
/**
* This needs to be called if the above caller returned true, once the above
* caller doesn't care about getting notified anymore.
*/
void DisassociateImage(const nsStyleImage&);
void DisassociateImage(const mozilla::StyleImage&);
enum class AllowCustomCursorImage {
No,

View File

@ -1355,8 +1355,7 @@ ImgDrawResult nsImageFrame::DisplayAltFeedback(gfxContext& aRenderingContext,
// Assert that we're not drawing a border-image here; if we were, we
// couldn't ignore the ImgDrawResult that PaintBorderWithStyleBorder
// returns.
MOZ_ASSERT(recessedBorder.mBorderImageSource.GetType() ==
eStyleImageType_Null);
MOZ_ASSERT(recessedBorder.mBorderImageSource.IsNone());
Unused << nsCSSRendering::PaintBorderWithStyleBorder(
PresContext(), aRenderingContext, this, inner, inner, recessedBorder,
@ -1538,8 +1537,7 @@ ImgDrawResult nsImageFrame::DisplayAltFeedbackWithoutLayer(
// Assert that we're not drawing a border-image here; if we were, we
// couldn't ignore the ImgDrawResult that PaintBorderWithStyleBorder
// returns.
MOZ_ASSERT(recessedBorder.mBorderImageSource.GetType() ==
eStyleImageType_Null);
MOZ_ASSERT(recessedBorder.mBorderImageSource.IsNone());
nsRect rect = nsRect(aPt, GetSize());
Unused << nsCSSRendering::CreateWebRenderCommandsForBorderWithStyleBorder(

View File

@ -702,9 +702,9 @@ ImgDrawResult nsCSSRendering::CreateWebRenderCommandsForBorderWithStyleBorder(
mozilla::layers::RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder,
const nsStyleBorder& aStyleBorder) {
auto& borderImage = aStyleBorder.mBorderImageSource;
// First try to create commands for simple borders.
nsStyleImageType type = aStyleBorder.mBorderImageSource.GetType();
if (type == eStyleImageType_Null) {
if (borderImage.IsNone()) {
CreateWebRenderCommandsForNullBorder(
aItem, aForFrame, aBorderArea, aBuilder, aResources, aSc, aStyleBorder);
return ImgDrawResult::SUCCESS;
@ -712,7 +712,7 @@ ImgDrawResult nsCSSRendering::CreateWebRenderCommandsForBorderWithStyleBorder(
// Next we try image and gradient borders. Gradients are not supported at
// this very moment.
if (type != eStyleImageType_Image) {
if (!borderImage.IsImageRequestType()) {
return ImgDrawResult::NOT_SUPPORTED;
}
@ -845,7 +845,7 @@ ImgDrawResult nsCSSRendering::PaintBorderWithStyleBorder(
}
}
if (!aStyleBorder.mBorderImageSource.IsEmpty()) {
if (!aStyleBorder.mBorderImageSource.IsNone()) {
ImgDrawResult result = ImgDrawResult::SUCCESS;
uint32_t irFlags = 0;
@ -873,7 +873,7 @@ ImgDrawResult nsCSSRendering::PaintBorderWithStyleBorder(
// If we had a border-image, but it wasn't loaded, then we should return
// ImgDrawResult::NOT_READY; we'll want to try again if we do a paint with
// sync decoding enabled.
if (aStyleBorder.mBorderImageSource.GetType() != eStyleImageType_Null) {
if (!aStyleBorder.mBorderImageSource.IsNone()) {
result = ImgDrawResult::NOT_READY;
}
@ -910,7 +910,7 @@ Maybe<nsCSSBorderRenderer> nsCSSRendering::CreateBorderRendererWithStyleBorder(
const nsRect& aDirtyRect, const nsRect& aBorderArea,
const nsStyleBorder& aStyleBorder, ComputedStyle* aStyle,
bool* aOutBorderIsEmpty, Sides aSkipSides) {
if (aStyleBorder.mBorderImageSource.GetType() != eStyleImageType_Null) {
if (!aStyleBorder.mBorderImageSource.IsNone()) {
return Nothing();
}
return CreateNullBorderRendererWithStyleBorder(
@ -1881,15 +1881,15 @@ bool nsCSSRendering::CanBuildWebRenderDisplayItemsForStyleImageLayer(
}
}
// We only support painting gradients and image for a single style image layer
const nsStyleImage* styleImage =
&aBackgroundStyle->mImage.mLayers[aLayer].mImage;
if (styleImage->GetType() == eStyleImageType_Image) {
if (styleImage->GetCropRect()) {
// We only support painting gradients and image for a single style image
// layer, and we don't support crop-rects.
const auto& styleImage = aBackgroundStyle->mImage.mLayers[aLayer].mImage;
if (styleImage.IsImageRequestType()) {
if (styleImage.IsRect()) {
return false;
}
imgRequestProxy* requestProxy = styleImage->GetImageData();
imgRequestProxy* requestProxy = styleImage.GetImageRequest();
if (!requestProxy) {
return false;
}
@ -1909,7 +1909,7 @@ bool nsCSSRendering::CanBuildWebRenderDisplayItemsForStyleImageLayer(
return true;
}
if (styleImage->GetType() == eStyleImageType_Gradient) {
if (styleImage.IsGradient()) {
return true;
}
@ -1966,8 +1966,9 @@ static bool IsOpaqueBorderEdge(const nsStyleBorder& aBorder,
// because we may not even have the image loaded at this point, and
// even if we did, checking whether the relevant tile is fully
// opaque would be too much work.
if (aBorder.mBorderImageSource.GetType() != eStyleImageType_Null)
if (!aBorder.mBorderImageSource.IsNone()) {
return false;
}
StyleColor color = aBorder.BorderColorFor(aSide);
// We don't know the foreground color here, so if it's being used

View File

@ -62,7 +62,7 @@ struct nsBackgroundLayerState {
/**
* @param aFlags some combination of nsCSSRendering::PAINTBG_* flags
*/
nsBackgroundLayerState(nsIFrame* aForFrame, const nsStyleImage* aImage,
nsBackgroundLayerState(nsIFrame* aForFrame, const mozilla::StyleImage* aImage,
uint32_t aFlags)
: mImageRenderer(aForFrame, aImage, aFlags) {}

View File

@ -3609,7 +3609,8 @@ ImgDrawResult nsCSSBorderImageRenderer::CreateWebRenderCommands(
ImgDrawResult drawResult = ImgDrawResult::SUCCESS;
switch (mImageRenderer.GetType()) {
case eStyleImageType_Image: {
case StyleImage::Tag::Rect:
case StyleImage::Tag::Url: {
RefPtr<imgIContainer> img = mImageRenderer.GetImage();
if (!img || img->GetType() == imgIContainer::TYPE_VECTOR) {
// Vector images will redraw each segment of the border up to 8 times.
@ -3693,7 +3694,7 @@ ImgDrawResult nsCSSBorderImageRenderer::CreateWebRenderCommands(
aBuilder.PushBorderImage(dest, clip, !aItem->BackfaceIsHidden(), params);
break;
}
case eStyleImageType_Gradient: {
case StyleImage::Tag::Gradient: {
const StyleGradient& gradient = *mImageRenderer.GetGradientData();
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
aForFrame->PresContext(), aForFrame->Style(), gradient, mImageSize);

View File

@ -3914,7 +3914,7 @@ nsDisplayBackgroundImage::GetInitData(nsDisplayListBuilder* aBuilder,
layer.mAttachment == StyleImageLayerAttachment::Fixed &&
!isTransformedFixed;
bool shouldFixToViewport = shouldTreatAsFixed && !layer.mImage.IsEmpty();
bool shouldFixToViewport = shouldTreatAsFixed && !layer.mImage.IsNone();
bool isRasterImage = state.mImageRenderer.IsRasterImage();
nsCOMPtr<imgIContainer> image;
if (isRasterImage) {
@ -4204,7 +4204,7 @@ bool nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
// Passing bg == nullptr in this macro will result in one iteration with
// i = 0.
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, bg->mImage) {
if (bg->mImage.mLayers[i].mImage.IsEmpty()) {
if (bg->mImage.mLayers[i].mImage.IsNone()) {
continue;
}
@ -4410,12 +4410,10 @@ nsDisplayBackgroundImage::ShouldCreateOwnLayer(nsDisplayListBuilder* aBuilder,
if (StaticPrefs::layout_animated_image_layers_enabled() && mBackgroundStyle) {
const nsStyleImageLayers::Layer& layer =
mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer];
const nsStyleImage* image = &layer.mImage;
if (image->GetType() == eStyleImageType_Image) {
imgIRequest* imgreq = image->GetImageData();
const auto* image = &layer.mImage;
if (auto* request = image->GetImageRequest()) {
nsCOMPtr<imgIContainer> image;
if (imgreq && NS_SUCCEEDED(imgreq->GetImage(getter_AddRefs(image))) &&
image) {
if (NS_SUCCEEDED(request->GetImage(getter_AddRefs(image))) && image) {
bool animated = false;
if (NS_SUCCEEDED(image->GetAnimated(&animated)) && animated) {
return WHENEVER_POSSIBLE;
@ -4734,9 +4732,9 @@ void nsDisplayBackgroundImage::ComputeInvalidationRegion(
return;
}
if (aBuilder->ShouldSyncDecodeImages()) {
const nsStyleImage& image =
const auto& image =
mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer].mImage;
if (image.GetType() == eStyleImageType_Image &&
if (image.IsImageRequestType() &&
geometry->ShouldInvalidateToSyncDecodeImages()) {
aInvalidRegion->Or(*aInvalidRegion, bounds);
}
@ -9884,8 +9882,8 @@ void nsDisplayMasksAndClipPaths::ComputeInvalidationRegion(
geometry->ShouldInvalidateToSyncDecodeImages()) {
const nsStyleSVGReset* svgReset = mFrame->StyleSVGReset();
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, svgReset->mMask) {
const nsStyleImage& image = svgReset->mMask.mLayers[i].mImage;
if (image.GetType() == eStyleImageType_Image) {
const auto& image = svgReset->mMask.mLayers[i].mImage;
if (image.IsImageRequestType()) {
aInvalidRegion->Or(*aInvalidRegion, bounds);
break;
}

View File

@ -46,10 +46,10 @@ nsSize CSSSizeOrRatio::ComputeConcreteSize() const {
}
nsImageRenderer::nsImageRenderer(nsIFrame* aForFrame,
const nsStyleImage* aImage, uint32_t aFlags)
const StyleImage* aImage, uint32_t aFlags)
: mForFrame(aForFrame),
mImage(aImage),
mType(aImage->GetType()),
mType(aImage->tag),
mImageContainer(nullptr),
mGradientData(nullptr),
mPaintServerFrame(nullptr),
@ -59,17 +59,13 @@ nsImageRenderer::nsImageRenderer(nsIFrame* aForFrame,
mExtendMode(ExtendMode::CLAMP),
mMaskOp(StyleMaskMode::MatchSource) {}
static bool ShouldTreatAsCompleteDueToSyncDecode(const nsStyleImage* aImage,
static bool ShouldTreatAsCompleteDueToSyncDecode(const StyleImage* aImage,
uint32_t aFlags) {
if (!(aFlags & nsImageRenderer::FLAG_SYNC_DECODE_IMAGES)) {
return false;
}
if (aImage->GetType() != eStyleImageType_Image) {
return false;
}
imgRequestProxy* req = aImage->GetImageData();
imgRequestProxy* req = aImage->GetImageRequest();
if (!req) {
return false;
}
@ -97,10 +93,10 @@ static bool ShouldTreatAsCompleteDueToSyncDecode(const nsStyleImage* aImage,
}
bool nsImageRenderer::PrepareImage() {
if (mImage->IsEmpty() ||
(mType == eStyleImageType_Image && !mImage->GetImageData())) {
// mImage->GetImageData() could be null here if the nsStyleImage refused
// to load a same-document URL.
if (mImage->IsNone() ||
(mImage->IsImageRequestType() && !mImage->GetImageRequest())) {
// mImage->GetImageRequest() could be null here if the StyleImage refused
// to load a same-document URL, or the url was invalid, for example.
mPrepareResult = ImgDrawResult::BAD_IMAGE;
return false;
}
@ -111,10 +107,10 @@ bool nsImageRenderer::PrepareImage() {
// Boost the loading priority since we know we want to draw the image.
if ((mFlags & nsImageRenderer::FLAG_PAINTING_TO_WINDOW) &&
mType == eStyleImageType_Image) {
MOZ_ASSERT(mImage->GetImageData(),
mImage->IsImageRequestType()) {
MOZ_ASSERT(mImage->GetImageRequest(),
"must have image data, since we checked above");
mImage->GetImageData()->BoostPriority(imgIRequest::CATEGORY_DISPLAY);
mImage->GetImageRequest()->BoostPriority(imgIRequest::CATEGORY_DISPLAY);
}
// Check again to see if we finished.
@ -128,75 +124,65 @@ bool nsImageRenderer::PrepareImage() {
}
}
switch (mType) {
case eStyleImageType_Image: {
MOZ_ASSERT(mImage->GetImageData(),
"must have image data, since we checked above");
nsCOMPtr<imgIContainer> srcImage;
DebugOnly<nsresult> rv =
mImage->GetImageData()->GetImage(getter_AddRefs(srcImage));
if (mImage->IsImageRequestType()) {
MOZ_ASSERT(mImage->GetImageRequest(),
"must have image data, since we checked above");
nsCOMPtr<imgIContainer> srcImage;
DebugOnly<nsresult> rv =
mImage->GetImageRequest()->GetImage(getter_AddRefs(srcImage));
MOZ_ASSERT(NS_SUCCEEDED(rv) && srcImage,
"If GetImage() is failing, mImage->IsComplete() "
"should have returned false");
if (!mImage->GetCropRect()) {
if (!mImage->IsRect()) {
mImageContainer.swap(srcImage);
} else {
auto croprect = mImage->ComputeActualCropRect();
if (!croprect || croprect->mRect.IsEmpty()) {
// The cropped image has zero size
mPrepareResult = ImgDrawResult::BAD_IMAGE;
return false;
}
if (croprect->mIsEntireImage) {
// The cropped image is identical to the source image
mImageContainer.swap(srcImage);
} else {
nsIntRect actualCropRect;
bool isEntireImage;
bool success =
mImage->ComputeActualCropRect(actualCropRect, &isEntireImage);
if (!success || actualCropRect.IsEmpty()) {
// The cropped image has zero size
mPrepareResult = ImgDrawResult::BAD_IMAGE;
return false;
}
if (isEntireImage) {
// The cropped image is identical to the source image
mImageContainer.swap(srcImage);
} else {
nsCOMPtr<imgIContainer> subImage =
ImageOps::Clip(srcImage, actualCropRect, Nothing());
mImageContainer.swap(subImage);
}
nsCOMPtr<imgIContainer> subImage =
ImageOps::Clip(srcImage, croprect->mRect, Nothing());
mImageContainer.swap(subImage);
}
mPrepareResult = ImgDrawResult::SUCCESS;
break;
}
case eStyleImageType_Gradient:
mGradientData = &mImage->GetGradient();
mPrepareResult = ImgDrawResult::SUCCESS;
break;
case eStyleImageType_Element: {
dom::Element* paintElement = // may be null
SVGObserverUtils::GetAndObserveBackgroundImage(
mForFrame->FirstContinuation(), mImage->GetElementId());
// If the referenced element is an <img>, <canvas>, or <video> element,
// prefer SurfaceFromElement as it's more reliable.
mImageElementSurface = nsLayoutUtils::SurfaceFromElement(paintElement);
mPrepareResult = ImgDrawResult::SUCCESS;
} else if (mImage->IsGradient()) {
mGradientData = &*mImage->AsGradient();
mPrepareResult = ImgDrawResult::SUCCESS;
} else if (mImage->IsElement()) {
dom::Element* paintElement = // may be null
SVGObserverUtils::GetAndObserveBackgroundImage(
mForFrame->FirstContinuation(), mImage->AsElement().AsAtom());
// If the referenced element is an <img>, <canvas>, or <video> element,
// prefer SurfaceFromElement as it's more reliable.
mImageElementSurface = nsLayoutUtils::SurfaceFromElement(paintElement);
if (!mImageElementSurface.GetSourceSurface()) {
nsIFrame* paintServerFrame =
paintElement ? paintElement->GetPrimaryFrame() : nullptr;
// If there's no referenced frame, or the referenced frame is
// non-displayable SVG, then we have nothing valid to paint.
if (!paintServerFrame ||
(paintServerFrame->IsFrameOfType(nsIFrame::eSVG) &&
!paintServerFrame->IsFrameOfType(nsIFrame::eSVGPaintServer) &&
!static_cast<nsSVGDisplayableFrame*>(
do_QueryFrame(paintServerFrame)))) {
mPrepareResult = ImgDrawResult::BAD_IMAGE;
return false;
}
mPaintServerFrame = paintServerFrame;
if (!mImageElementSurface.GetSourceSurface()) {
nsIFrame* paintServerFrame =
paintElement ? paintElement->GetPrimaryFrame() : nullptr;
// If there's no referenced frame, or the referenced frame is
// non-displayable SVG, then we have nothing valid to paint.
if (!paintServerFrame ||
(paintServerFrame->IsFrameOfType(nsIFrame::eSVG) &&
!paintServerFrame->IsFrameOfType(nsIFrame::eSVGPaintServer) &&
!static_cast<nsSVGDisplayableFrame*>(
do_QueryFrame(paintServerFrame)))) {
mPrepareResult = ImgDrawResult::BAD_IMAGE;
return false;
}
mPrepareResult = ImgDrawResult::SUCCESS;
break;
mPaintServerFrame = paintServerFrame;
}
case eStyleImageType_Null:
default:
break;
mPrepareResult = ImgDrawResult::SUCCESS;
} else {
MOZ_ASSERT(mImage->IsNone(), "Unknown image type?");
}
return IsReady();
@ -209,7 +195,8 @@ CSSSizeOrRatio nsImageRenderer::ComputeIntrinsicSize() {
CSSSizeOrRatio result;
switch (mType) {
case eStyleImageType_Image: {
case StyleImage::Tag::Rect:
case StyleImage::Tag::Url: {
bool haveWidth, haveHeight;
CSSIntSize imageIntSize;
nsLayoutUtils::ComputeSizeForDrawing(
@ -235,7 +222,7 @@ CSSSizeOrRatio nsImageRenderer::ComputeIntrinsicSize() {
break;
}
case eStyleImageType_Element: {
case StyleImage::Tag::Element: {
// XXX element() should have the width/height of the referenced element,
// and that element's ratio, if it matches. If it doesn't match, it
// should have no width/height or ratio. See element() in CSS images:
@ -265,11 +252,10 @@ CSSSizeOrRatio nsImageRenderer::ComputeIntrinsicSize() {
}
break;
}
case eStyleImageType_Gradient:
// Per <http://dev.w3.org/csswg/css3-images/#gradients>, gradients have no
// intrinsic dimensions.
case eStyleImageType_Null:
default:
// Per <http://dev.w3.org/csswg/css3-images/#gradients>, gradients have no
// intrinsic dimensions.
case StyleImage::Tag::Gradient:
case StyleImage::Tag::None:
break;
}
@ -487,14 +473,15 @@ ImgDrawResult nsImageRenderer::Draw(nsPresContext* aPresContext,
}
switch (mType) {
case eStyleImageType_Image: {
case StyleImage::Tag::Rect:
case StyleImage::Tag::Url: {
result = nsLayoutUtils::DrawBackgroundImage(
*ctx, mForFrame, aPresContext, mImageContainer, samplingFilter, aDest,
aFill, aRepeatSize, aAnchor, aDirtyRect,
ConvertImageRendererToDrawFlags(mFlags), mExtendMode, aOpacity);
break;
}
case eStyleImageType_Gradient: {
case StyleImage::Tag::Gradient: {
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
aPresContext, mForFrame->Style(), *mGradientData, mSize);
@ -502,7 +489,7 @@ ImgDrawResult nsImageRenderer::Draw(nsPresContext* aPresContext,
aOpacity);
break;
}
case eStyleImageType_Element: {
case StyleImage::Tag::Element: {
RefPtr<gfxDrawable> drawable = DrawableForElement(aDest, *ctx);
if (!drawable) {
NS_WARNING("Could not create drawable for element");
@ -516,8 +503,7 @@ ImgDrawResult nsImageRenderer::Draw(nsPresContext* aPresContext,
aOpacity);
break;
}
case eStyleImageType_Null:
default:
case StyleImage::Tag::None:
break;
}
@ -573,7 +559,7 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
ImgDrawResult drawResult = ImgDrawResult::SUCCESS;
switch (mType) {
case eStyleImageType_Gradient: {
case StyleImage::Tag::Gradient: {
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
aPresContext, mForFrame->Style(), *mGradientData, mSize);
@ -582,7 +568,8 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
!aItem->BackfaceIsHidden(), aOpacity);
break;
}
case eStyleImageType_Image: {
case StyleImage::Tag::Rect:
case StyleImage::Tag::Url: {
uint32_t containerFlags = imgIContainer::FLAG_ASYNC_NOTIFY;
if (mFlags & nsImageRenderer::FLAG_PAINTING_TO_WINDOW) {
containerFlags |= imgIContainer::FLAG_HIGH_QUALITY_SCALING;
@ -684,7 +671,7 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
already_AddRefed<gfxDrawable> nsImageRenderer::DrawableForElement(
const nsRect& aImageRect, gfxContext& aContext) {
NS_ASSERTION(mType == eStyleImageType_Element,
NS_ASSERTION(mType == StyleImage::Tag::Element,
"DrawableForElement only makes sense if backed by an element");
if (mPaintServerFrame) {
// XXX(seth): In order to not pass FLAG_SYNC_DECODE_IMAGES here,
@ -878,7 +865,11 @@ ImgDrawResult nsImageRenderer::DrawBorderImageComponent(
return ImgDrawResult::SUCCESS;
}
if (mType == eStyleImageType_Image || mType == eStyleImageType_Element) {
const bool isRequestBacked = mType == StyleImage::Tag::Url ||
mType == StyleImage::Tag::Rect;
MOZ_ASSERT(isRequestBacked == mImage->IsImageRequestType());
if (isRequestBacked || mType == StyleImage::Tag::Element) {
nsCOMPtr<imgIContainer> subImage;
// To draw one portion of an image into a border component, we stretch that
@ -897,7 +888,7 @@ ImgDrawResult nsImageRenderer::DrawBorderImageComponent(
}
// Retrieve or create the subimage we'll draw.
nsIntRect srcRect(aSrc.x, aSrc.y, aSrc.width, aSrc.height);
if (mType == eStyleImageType_Image) {
if (isRequestBacked) {
CachedBorderImageData* cachedData =
mForFrame->GetProperty(nsIFrame::CachedBorderImageDataProperty());
if (!cachedData) {
@ -988,82 +979,62 @@ ImgDrawResult nsImageRenderer::DrawShapeImage(nsPresContext* aPresContext,
return ImgDrawResult::SUCCESS;
}
ImgDrawResult result = ImgDrawResult::SUCCESS;
switch (mType) {
case eStyleImageType_Image: {
uint32_t drawFlags =
ConvertImageRendererToDrawFlags(mFlags) | imgIContainer::FRAME_FIRST;
nsRect dest(nsPoint(0, 0), mSize);
// We have a tricky situation in our choice of SamplingFilter. Shape
// images define a float area based on the alpha values in the rendered
// pixels. When multiple device pixels are used for one css pixel, the
// sampling can change crisp edges into aliased edges. For visual pixels,
// that's usually the right choice. For defining a float area, it can
// cause problems. If a style is using a shape-image-threshold value that
// is less than the alpha of the edge pixels, any filtering may smear the
// alpha into adjacent pixels and expand the float area in a confusing
// way. Since the alpha threshold can be set precisely in CSS, and since a
// web author may be counting on that threshold to define a precise float
// area from an image, it is least confusing to have the rendered pixels
// have unfiltered alpha. We use SamplingFilter::POINT to ensure that each
// rendered pixel has an alpha that precisely matches the alpha of the
// closest pixel in the image.
result = nsLayoutUtils::DrawSingleImage(
aRenderingContext, aPresContext, mImageContainer,
SamplingFilter::POINT, dest, dest, Nothing(), drawFlags, nullptr,
nullptr);
break;
}
case eStyleImageType_Gradient: {
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
aPresContext, mForFrame->Style(), *mGradientData, mSize);
nsRect dest(nsPoint(0, 0), mSize);
renderer.Paint(aRenderingContext, dest, dest, mSize,
CSSIntRect::FromAppUnitsRounded(dest), dest, 1.0);
break;
}
default:
// Unsupported image type.
result = ImgDrawResult::BAD_IMAGE;
break;
if (mImage->IsImageRequestType()) {
uint32_t drawFlags =
ConvertImageRendererToDrawFlags(mFlags) | imgIContainer::FRAME_FIRST;
nsRect dest(nsPoint(0, 0), mSize);
// We have a tricky situation in our choice of SamplingFilter. Shape
// images define a float area based on the alpha values in the rendered
// pixels. When multiple device pixels are used for one css pixel, the
// sampling can change crisp edges into aliased edges. For visual pixels,
// that's usually the right choice. For defining a float area, it can
// cause problems. If a style is using a shape-image-threshold value that
// is less than the alpha of the edge pixels, any filtering may smear the
// alpha into adjacent pixels and expand the float area in a confusing
// way. Since the alpha threshold can be set precisely in CSS, and since a
// web author may be counting on that threshold to define a precise float
// area from an image, it is least confusing to have the rendered pixels
// have unfiltered alpha. We use SamplingFilter::POINT to ensure that each
// rendered pixel has an alpha that precisely matches the alpha of the
// closest pixel in the image.
return nsLayoutUtils::DrawSingleImage(
aRenderingContext, aPresContext, mImageContainer,
SamplingFilter::POINT, dest, dest, Nothing(), drawFlags, nullptr,
nullptr);
}
return result;
if (mImage->IsGradient()) {
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
aPresContext, mForFrame->Style(), *mGradientData, mSize);
nsRect dest(nsPoint(0, 0), mSize);
renderer.Paint(aRenderingContext, dest, dest, mSize,
CSSIntRect::FromAppUnitsRounded(dest), dest, 1.0);
return ImgDrawResult::SUCCESS;
}
// Unsupported image type.
return ImgDrawResult::BAD_IMAGE;
}
bool nsImageRenderer::IsRasterImage() {
if (mType != eStyleImageType_Image || !mImageContainer) return false;
return mImageContainer->GetType() == imgIContainer::TYPE_RASTER;
return mImageContainer &&
mImageContainer->GetType() == imgIContainer::TYPE_RASTER;
}
bool nsImageRenderer::IsAnimatedImage() {
if (mType != eStyleImageType_Image || !mImageContainer) return false;
bool animated = false;
if (NS_SUCCEEDED(mImageContainer->GetAnimated(&animated)) && animated)
return true;
return false;
return mImageContainer &&
NS_SUCCEEDED(mImageContainer->GetAnimated(&animated)) && animated;
}
already_AddRefed<imgIContainer> nsImageRenderer::GetImage() {
if (mType != eStyleImageType_Image || !mImageContainer) {
return nullptr;
}
nsCOMPtr<imgIContainer> image = mImageContainer;
return image.forget();
return do_AddRef(mImageContainer);
}
bool nsImageRenderer::IsImageContainerAvailable(layers::LayerManager* aManager,
uint32_t aFlags) {
if (!mImageContainer) {
return false;
}
return mImageContainer->IsImageContainerAvailable(aManager, aFlags);
return mImageContainer &&
mImageContainer->IsImageContainerAvailable(aManager, aFlags);
}
void nsImageRenderer::PurgeCacheForViewportChange(

View File

@ -85,8 +85,8 @@ struct CSSSizeOrRatio {
/**
* This is a small wrapper class to encapsulate image drawing that can draw an
* nsStyleImage image, which may internally be a real image, a sub image, or a
* CSS gradient.
* StyleImage image, which may internally be a real image, a sub image, or a CSS
* gradient, etc...
*
* @note Always call the member functions in the order of PrepareImage(),
* SetSize(), and Draw*().
@ -100,7 +100,7 @@ class nsImageRenderer {
enum { FLAG_SYNC_DECODE_IMAGES = 0x01, FLAG_PAINTING_TO_WINDOW = 0x02 };
enum FitType { CONTAIN, COVER };
nsImageRenderer(nsIFrame* aForFrame, const nsStyleImage* aImage,
nsImageRenderer(nsIFrame* aForFrame, const mozilla::StyleImage* aImage,
uint32_t aFlags);
~nsImageRenderer() = default;
/**
@ -248,7 +248,7 @@ class nsImageRenderer {
void PurgeCacheForViewportChange(
const mozilla::Maybe<nsSize>& aSVGViewportSize, const bool aHasRatio);
const nsSize& GetSize() const { return mSize; }
nsStyleImageType GetType() const { return mType; }
mozilla::StyleImage::Tag GetType() const { return mType; }
const mozilla::StyleGradient* GetGradientData() const {
return mGradientData;
}
@ -286,15 +286,15 @@ class nsImageRenderer {
/**
* Helper method for creating a gfxDrawable from mPaintServerFrame or
* mImageElementSurface.
* Requires mType is eStyleImageType_Element.
* Requires mType to be Element.
* Returns null if we cannot create the drawable.
*/
already_AddRefed<gfxDrawable> DrawableForElement(const nsRect& aImageRect,
gfxContext& aContext);
nsIFrame* mForFrame;
const nsStyleImage* mImage;
nsStyleImageType mType;
const mozilla::StyleImage* mImage;
mozilla::StyleImage::Tag mType;
nsCOMPtr<imgIContainer> mImageContainer;
const mozilla::StyleGradient* mGradientData;
nsIFrame* mPaintServerFrame;

View File

@ -1105,43 +1105,6 @@ const AnonymousCounterStyle* Gecko_CounterStyle_GetAnonymous(
return aPtr->AsAnonymous();
}
void Gecko_SetNullImageValue(nsStyleImage* aImage) {
MOZ_ASSERT(aImage);
aImage->SetNull();
}
void Gecko_SetGradientImageValue(nsStyleImage* aImage,
StyleGradient* aGradient) {
MOZ_ASSERT(aImage);
aImage->SetGradientData(UniquePtr<StyleGradient>(aGradient));
}
void Gecko_SetLayerImageImageValue(nsStyleImage* aImage,
const StyleComputedImageUrl* aUrl) {
MOZ_ASSERT(aImage && aUrl);
aImage->SetImageUrl(*aUrl);
}
void Gecko_SetImageElement(nsStyleImage* aImage, nsAtom* aAtom) {
MOZ_ASSERT(aImage);
aImage->SetElementId(do_AddRef(aAtom));
}
void Gecko_CopyImageValueFrom(nsStyleImage* aImage,
const nsStyleImage* aOther) {
MOZ_ASSERT(aImage);
MOZ_ASSERT(aOther);
*aImage = *aOther;
}
void Gecko_InitializeImageCropRect(nsStyleImage* aImage) {
MOZ_ASSERT(aImage);
auto zero = StyleNumberOrPercentage::Number(0);
aImage->SetCropRect(MakeUnique<nsStyleImage::CropRect>(
nsStyleImage::CropRect{zero, zero, zero, zero}));
}
void Gecko_SetCursorArrayCapacity(nsStyleUI* aUi, size_t aCapacity) {
aUi->mCursorImages.Clear();
aUi->mCursorImages.SetCapacity(aCapacity);
@ -1156,11 +1119,6 @@ void Gecko_CopyCursorArrayFrom(nsStyleUI* aDest, const nsStyleUI* aSrc) {
aDest->mCursorImages = aSrc->mCursorImages;
}
nsAtom* Gecko_GetImageElement(const nsStyleImage* aImage) {
MOZ_ASSERT(aImage && aImage->GetType() == eStyleImageType_Element);
return const_cast<nsAtom*>(aImage->GetElementId());
}
void Gecko_EnsureTArrayCapacity(void* aArray, size_t aCapacity,
size_t aElemSize) {
auto base = reinterpret_cast<
@ -1318,7 +1276,7 @@ void Gecko_DestroyShapeSource(StyleShapeSource* aShape) {
}
void Gecko_NewShapeImage(StyleShapeSource* aShape) {
aShape->SetShapeImage(MakeUnique<nsStyleImage>());
aShape->SetShapeImage(MakeUnique<StyleImage>(StyleImage::None()));
}
void Gecko_SetToSVGPath(StyleShapeSource* aShape,

View File

@ -336,21 +336,6 @@ nsAtom* Gecko_CounterStyle_GetName(const mozilla::CounterStylePtr* ptr);
const mozilla::AnonymousCounterStyle* Gecko_CounterStyle_GetAnonymous(
const mozilla::CounterStylePtr* ptr);
// background-image style.
void Gecko_SetNullImageValue(nsStyleImage* image);
// NOTE: Takes ownership of the gradient.
void Gecko_SetGradientImageValue(nsStyleImage*, mozilla::StyleGradient*);
void Gecko_SetLayerImageImageValue(nsStyleImage* image,
const mozilla::StyleComputedImageUrl* url);
void Gecko_SetImageElement(nsStyleImage* image, nsAtom* atom);
void Gecko_CopyImageValueFrom(nsStyleImage* image, const nsStyleImage* other);
void Gecko_InitializeImageCropRect(nsStyleImage* image);
nsAtom* Gecko_GetImageElement(const nsStyleImage* image);
// list-style-image style.
void Gecko_SetListStyleImageNone(nsStyleList* style_struct);

View File

@ -564,6 +564,7 @@ cbindgen-types = [
{ gecko = "StyleAlignContent", servo = "values::computed::align::AlignContent" },
{ gecko = "StyleJustifyContent", servo = "values::computed::align::JustifyContent" },
{ gecko = "StyleComputedValueFlags", servo = "computed_value_flags::ComputedValueFlags" },
{ gecko = "StyleImage", servo = "values::computed::Image" },
]
mapped-generic-types = [

View File

@ -912,6 +912,48 @@ inline RestyleHint RestyleHint::ForAnimations() {
RestyleHint::RESTYLE_CSS_ANIMATIONS | RestyleHint::RESTYLE_SMIL;
}
template <>
inline bool StyleImage::IsImageRequestType() const {
return IsUrl() || IsRect();
}
template <>
inline const StyleComputedImageUrl* StyleImage::GetImageRequestURLValue()
const {
if (IsUrl()) {
return &AsUrl();
}
if (IsRect()) {
return &AsRect()->url;
}
return nullptr;
}
template <>
inline imgRequestProxy* StyleImage::GetImageRequest() const {
auto* url = GetImageRequestURLValue();
return url ? url->GetImage() : nullptr;
}
template <>
inline bool StyleImage::IsResolved() const {
auto* url = GetImageRequestURLValue();
return !url || url->IsImageResolved();
}
template <>
bool StyleImage::IsOpaque() const;
template <>
bool StyleImage::IsSizeAvailable() const;
template <>
bool StyleImage::IsComplete() const;
template <>
bool StyleImage::StartDecoding() const;
template <>
Maybe<StyleImage::ActualCropRect> StyleImage::ComputeActualCropRect() const;
template <>
void StyleImage::ResolveImage(dom::Document&, const StyleImage*);
} // namespace mozilla
#endif

View File

@ -626,9 +626,9 @@ static void AddImageURL(const StyleComputedUrl& aURL,
}
}
static void AddImageURL(const nsStyleImage& aImage,
static void AddImageURL(const StyleImage& aImage,
nsTArray<nsCString>& aURLs) {
if (auto* urlValue = aImage.GetURLValue()) {
if (auto* urlValue = aImage.GetImageRequestURLValue()) {
AddImageURL(*urlValue, aURLs);
}
}
@ -2494,14 +2494,13 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetMask() {
firstLayer.mPosition, nsStyleImageLayers::LayerType::Mask) ||
!firstLayer.mRepeat.IsInitialValue() ||
!firstLayer.mSize.IsInitialValue() ||
!(firstLayer.mImage.GetType() == eStyleImageType_Null ||
firstLayer.mImage.GetType() == eStyleImageType_Image)) {
!(firstLayer.mImage.IsNone() || firstLayer.mImage.IsUrl())) {
return nullptr;
}
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
SetValueToURLValue(firstLayer.mImage.GetURLValue(), val);
SetValueToURLValue(firstLayer.mImage.GetImageRequestURLValue(), val);
return val.forget();
}

View File

@ -41,7 +41,6 @@ class nsDOMCSSValueList;
struct nsMargin;
class nsROCSSPrimitiveValue;
class nsStyleGradient;
struct nsStyleImage;
class nsComputedDOMStyle final : public nsDOMCSSDeclaration,
public nsStubMutationObserver {

View File

@ -409,6 +409,7 @@ static inline BorderRadius ZeroBorderRadius() {
nsStyleBorder::nsStyleBorder(const Document& aDocument)
: mBorderRadius(ZeroBorderRadius()),
mBorderImageSource(StyleImage::None()),
mBorderImageWidth(
StyleRectWithAllSides(StyleBorderImageSideWidth::Number(1.))),
mBorderImageOutset(
@ -535,7 +536,7 @@ nsChangeHint nsStyleBorder::CalcDifference(
// while CalcDifference might be executed on a background thread. As a
// result, we have to check mBorderImage* fields even before border image was
// actually loaded.
if (!mBorderImageSource.IsEmpty() || !aNewData.mBorderImageSource.IsEmpty()) {
if (!mBorderImageSource.IsNone() || !aNewData.mBorderImageSource.IsNone()) {
if (mBorderImageSource != aNewData.mBorderImageSource ||
mBorderImageRepeatH != aNewData.mBorderImageRepeatH ||
mBorderImageRepeatV != aNewData.mBorderImageRepeatV ||
@ -1000,10 +1001,10 @@ bool StyleShapeSource::operator==(const StyleShapeSource& aOther) const {
return true;
}
void StyleShapeSource::SetShapeImage(UniquePtr<nsStyleImage> aShapeImage) {
void StyleShapeSource::SetShapeImage(UniquePtr<StyleImage> aShapeImage) {
MOZ_ASSERT(aShapeImage);
DoDestroy();
new (&mShapeImage) UniquePtr<nsStyleImage>(std::move(aShapeImage));
new (&mShapeImage) UniquePtr<StyleImage>(std::move(aShapeImage));
mType = StyleShapeSourceType::Image;
}
@ -1011,10 +1012,7 @@ imgIRequest* StyleShapeSource::GetShapeImageData() const {
if (mType != StyleShapeSourceType::Image) {
return nullptr;
}
if (mShapeImage->GetType() != eStyleImageType_Image) {
return nullptr;
}
return mShapeImage->GetImageData();
return mShapeImage->GetImageRequest();
}
void StyleShapeSource::SetBasicShape(UniquePtr<StyleBasicShape> aBasicShape,
@ -1060,7 +1058,7 @@ void StyleShapeSource::DoCopy(const StyleShapeSource& aOther) {
break;
case StyleShapeSourceType::Image:
SetShapeImage(MakeUnique<nsStyleImage>(aOther.ShapeImage()));
SetShapeImage(MakeUnique<StyleImage>(aOther.ShapeImage()));
break;
case StyleShapeSourceType::Shape: {
@ -1088,7 +1086,7 @@ void StyleShapeSource::DoDestroy() {
mBasicShape.~UniquePtr<StyleBasicShape>();
break;
case StyleShapeSourceType::Image:
mShapeImage.~UniquePtr<nsStyleImage>();
mShapeImage.~UniquePtr<StyleImage>();
break;
case StyleShapeSourceType::Path:
mSVGPath.~UniquePtr<StyleSVGPath>();
@ -1151,33 +1149,32 @@ void nsStyleSVGReset::TriggerImageLoads(Document& aDocument,
// NOTE(emilio): we intentionally don't call TriggerImageLoads for clip-path.
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, mMask) {
nsStyleImage& image = mMask.mLayers[i].mImage;
if (image.GetType() == eStyleImageType_Image) {
const auto* url = image.GetURLValue();
// If the url is a local ref, it must be a <mask-resource>, so we don't
// need to resolve the style image.
if (url->IsLocalRef()) {
continue;
}
#if 0
// XXX The old style system also checks whether this is a reference to
// the current document with reference, but it doesn't seem to be a
// behavior mentioned anywhere, so we comment out the code for now.
nsIURI* docURI = aPresContext->Document()->GetDocumentURI();
if (url->EqualsExceptRef(docURI)) {
continue;
}
#endif
// Otherwise, we may need the image even if it has a reference, in case
// the referenced element isn't a valid SVG <mask> element.
const nsStyleImage* oldImage =
(aOldStyle && aOldStyle->mMask.mLayers.Length() > i)
? &aOldStyle->mMask.mLayers[i].mImage
: nullptr;
image.ResolveImage(aDocument, oldImage);
auto& image = mMask.mLayers[i].mImage;
if (!image.IsImageRequestType()) {
continue;
}
const auto* url = image.GetImageRequestURLValue();
// If the url is a local ref, it must be a <mask-resource>, so we don't
// need to resolve the style image.
if (url->IsLocalRef()) {
continue;
}
#if 0
// XXX The old style system also checks whether this is a reference to
// the current document with reference, but it doesn't seem to be a
// behavior mentioned anywhere, so we comment out the code for now.
nsIURI* docURI = aPresContext->Document()->GetDocumentURI();
if (url->EqualsExceptRef(docURI)) {
continue;
}
#endif
// Otherwise, we may need the image even if it has a reference, in case
// the referenced element isn't a valid SVG <mask> element.
const auto* oldImage = (aOldStyle && aOldStyle->mMask.mLayers.Length() > i)
? &aOldStyle->mMask.mLayers[i].mImage
: nullptr;
image.ResolveImage(aDocument, oldImage);
}
}
@ -1221,7 +1218,7 @@ nsChangeHint nsStyleSVGReset::CalcDifference(
bool nsStyleSVGReset::HasMask() const {
for (uint32_t i = 0; i < mMask.mImageCount; i++) {
if (!mMask.mLayers[i].mImage.IsEmpty()) {
if (!mMask.mLayers[i].mImage.IsNone()) {
return true;
}
}
@ -1605,104 +1602,6 @@ void CachedBorderImageData::PurgeCacheForViewportChange(
}
}
// --------------------
// nsStyleImage
//
nsStyleImage::nsStyleImage() : mCropRect(nullptr), mType(eStyleImageType_Null) {
MOZ_COUNT_CTOR(nsStyleImage);
}
nsStyleImage::~nsStyleImage() {
MOZ_COUNT_DTOR(nsStyleImage);
if (mType != eStyleImageType_Null) {
SetNull();
}
}
nsStyleImage::nsStyleImage(const nsStyleImage& aOther)
: 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);
DoCopy(aOther);
}
nsStyleImage& nsStyleImage::operator=(const nsStyleImage& aOther) {
if (this != &aOther) {
DoCopy(aOther);
}
return *this;
}
void nsStyleImage::DoCopy(const nsStyleImage& aOther) {
SetNull();
if (aOther.mType == eStyleImageType_Image) {
SetImageUrl(aOther.mImage);
} else if (aOther.mType == eStyleImageType_Gradient) {
SetGradientData(MakeUnique<StyleGradient>(*aOther.mGradient));
} else if (aOther.mType == eStyleImageType_Element) {
SetElementId(do_AddRef(aOther.mElementId));
}
UniquePtr<CropRect> cropRectCopy;
if (aOther.mCropRect) {
cropRectCopy = MakeUnique<CropRect>(*aOther.mCropRect.get());
}
SetCropRect(std::move(cropRectCopy));
}
void nsStyleImage::SetNull() {
if (mType == eStyleImageType_Gradient) {
delete mGradient;
mGradient = nullptr;
} else if (mType == eStyleImageType_Image) {
mImage.~StyleComputedImageUrl();
} else if (mType == eStyleImageType_Element) {
NS_RELEASE(mElementId);
}
mType = eStyleImageType_Null;
mCropRect = nullptr;
}
void nsStyleImage::SetImageUrl(const StyleComputedImageUrl& aImage) {
if (mType != eStyleImageType_Null) {
SetNull();
}
new (&mImage) StyleComputedImageUrl(aImage);
mType = eStyleImageType_Image;
}
void nsStyleImage::SetGradientData(UniquePtr<StyleGradient> aGradient) {
MOZ_ASSERT(aGradient);
if (mType != eStyleImageType_Null) {
SetNull();
}
mGradient = aGradient.release();
mType = eStyleImageType_Gradient;
}
void nsStyleImage::SetElementId(already_AddRefed<nsAtom> aElementId) {
if (mType != eStyleImageType_Null) {
SetNull();
}
if (RefPtr<nsAtom> atom = aElementId) {
mElementId = atom.forget().take();
mType = eStyleImageType_Element;
}
}
void nsStyleImage::SetCropRect(UniquePtr<CropRect> aCropRect) {
mCropRect = std::move(aCropRect);
}
static int32_t ConvertToPixelCoord(const StyleNumberOrPercentage& aCoord,
int32_t aPercentScale) {
double pixelValue;
@ -1717,109 +1616,105 @@ static int32_t ConvertToPixelCoord(const StyleNumberOrPercentage& aCoord,
return NS_lround(pixelValue);
}
bool nsStyleImage::ComputeActualCropRect(nsIntRect& aActualCropRect,
bool* aIsEntireImage) const {
MOZ_ASSERT(mType == eStyleImageType_Image,
"This function is designed to be used only when mType"
"is eStyleImageType_Image.");
template <>
Maybe<StyleImage::ActualCropRect> StyleImage::ComputeActualCropRect() const {
MOZ_ASSERT(IsRect(),
"This function is designed to be used only image-rect images");
imgRequestProxy* req = GetImageData();
imgRequestProxy* req = GetImageRequest();
if (!req) {
return false;
return Nothing();
}
nsCOMPtr<imgIContainer> imageContainer;
req->GetImage(getter_AddRefs(imageContainer));
if (!imageContainer) {
return false;
return Nothing();
}
nsIntSize imageSize;
imageContainer->GetWidth(&imageSize.width);
imageContainer->GetHeight(&imageSize.height);
if (imageSize.width <= 0 || imageSize.height <= 0) {
return false;
return Nothing();
}
int32_t left =
ConvertToPixelCoord(mCropRect->Get(eSideLeft), imageSize.width);
int32_t top = ConvertToPixelCoord(mCropRect->Get(eSideTop), imageSize.height);
int32_t right =
ConvertToPixelCoord(mCropRect->Get(eSideRight), imageSize.width);
int32_t bottom =
ConvertToPixelCoord(mCropRect->Get(eSideBottom), imageSize.height);
auto& rect = AsRect();
int32_t left = ConvertToPixelCoord(rect->left, imageSize.width);
int32_t top = ConvertToPixelCoord(rect->top, imageSize.height);
int32_t right = ConvertToPixelCoord(rect->right, imageSize.width);
int32_t bottom = ConvertToPixelCoord(rect->bottom, imageSize.height);
// IntersectRect() returns an empty rect if we get negative width or height
nsIntRect cropRect(left, top, right - left, bottom - top);
nsIntRect imageRect(nsIntPoint(0, 0), imageSize);
aActualCropRect.IntersectRect(imageRect, cropRect);
if (aIsEntireImage) {
*aIsEntireImage = aActualCropRect.IsEqualInterior(imageRect);
}
return true;
auto finalRect = imageRect.Intersect(cropRect);
bool isEntireImage = finalRect.IsEqualInterior(imageRect);
return Some(ActualCropRect{finalRect, isEntireImage});
}
bool nsStyleImage::StartDecoding() const {
if (mType == eStyleImageType_Image) {
imgRequestProxy* req = GetImageData();
if (!req) {
return false;
}
return req->StartDecodingWithResult(imgIContainer::FLAG_ASYNC_NOTIFY);
template <>
bool StyleImage::StartDecoding() const {
if (IsImageRequestType()) {
imgRequestProxy* req = GetImageRequest();
return req &&
req->StartDecodingWithResult(imgIContainer::FLAG_ASYNC_NOTIFY);
}
// null image types always return false from IsComplete, so we do the same
// here.
return mType != eStyleImageType_Null;
// None always returns false from IsComplete, so we do the same here.
return !IsNone();
}
bool nsStyleImage::IsOpaque() const {
template <>
bool StyleImage::IsOpaque() const {
if (!IsComplete()) {
return false;
}
if (mType == eStyleImageType_Gradient) {
return mGradient->IsOpaque();
if (IsGradient()) {
return AsGradient()->IsOpaque();
}
if (mType == eStyleImageType_Element) {
if (IsElement()) {
return false;
}
MOZ_ASSERT(mType == eStyleImageType_Image, "unexpected image type");
MOZ_ASSERT(GetImageData(), "should've returned earlier above");
MOZ_ASSERT(IsImageRequestType(), "unexpected image type");
MOZ_ASSERT(GetImageRequest(), "should've returned earlier above");
nsCOMPtr<imgIContainer> imageContainer;
GetImageData()->GetImage(getter_AddRefs(imageContainer));
GetImageRequest()->GetImage(getter_AddRefs(imageContainer));
MOZ_ASSERT(imageContainer, "IsComplete() said image container is ready");
// Check if the crop region of the image is opaque.
if (imageContainer->WillDrawOpaqueNow()) {
if (!mCropRect) {
if (!IsRect()) {
return true;
}
// Must make sure if mCropRect contains at least a pixel.
// Must make sure if the crop rect contains at least a pixel.
// XXX Is this optimization worth it? Maybe I should just return false.
nsIntRect actualCropRect;
return ComputeActualCropRect(actualCropRect) && !actualCropRect.IsEmpty();
auto croprect = ComputeActualCropRect();
return croprect && !croprect->mRect.IsEmpty();
}
return false;
}
bool nsStyleImage::IsComplete() const {
switch (mType) {
case eStyleImageType_Null:
template <>
bool StyleImage::IsComplete() const {
switch (tag) {
case Tag::None:
return false;
case eStyleImageType_Gradient:
case eStyleImageType_Element:
case Tag::Gradient:
case Tag::Element:
return true;
case eStyleImageType_Image: {
case Tag::Url:
case Tag::Rect: {
if (!IsResolved()) {
return false;
}
imgRequestProxy* req = GetImageData();
imgRequestProxy* req = GetImageRequest();
if (!req) {
return false;
}
@ -1834,15 +1729,17 @@ bool nsStyleImage::IsComplete() const {
}
}
bool nsStyleImage::IsSizeAvailable() const {
switch (mType) {
case eStyleImageType_Null:
template <>
bool StyleImage::IsSizeAvailable() const {
switch (tag) {
case Tag::None:
return false;
case eStyleImageType_Gradient:
case eStyleImageType_Element:
case Tag::Gradient:
case Tag::Element:
return true;
case eStyleImageType_Image: {
imgRequestProxy* req = GetImageData();
case Tag::Url:
case Tag::Rect: {
imgRequestProxy* req = GetImageRequest();
if (!req) {
return false;
}
@ -1857,47 +1754,16 @@ bool nsStyleImage::IsSizeAvailable() const {
}
}
static inline bool EqualRects(const nsStyleImage::CropRect* aRect1,
const nsStyleImage::CropRect* aRect2) {
return aRect1 == aRect2 || /* handles null== null, and optimize */
(aRect1 && aRect2 && *aRect1 == *aRect2);
}
bool nsStyleImage::operator==(const nsStyleImage& aOther) const {
if (mType != aOther.mType) {
return false;
template <>
void StyleImage::ResolveImage(Document& aDoc, const StyleImage* aOld) {
if (IsResolved()) {
return;
}
if (!EqualRects(mCropRect.get(), aOther.mCropRect.get())) {
return false;
}
if (mType == eStyleImageType_Image) {
return mImage == aOther.mImage;
}
if (mType == eStyleImageType_Gradient) {
return *mGradient == *aOther.mGradient;
}
if (mType == eStyleImageType_Element) {
return mElementId == aOther.mElementId;
}
return true;
}
already_AddRefed<nsIURI> nsStyleImage::GetImageURI() const {
if (mType != eStyleImageType_Image) {
return nullptr;
}
nsCOMPtr<nsIURI> uri = mImage.GetURI();
return uri.forget();
}
const StyleComputedImageUrl* nsStyleImage::GetURLValue() const {
return mType == eStyleImageType_Image ? &mImage : nullptr;
auto* old = aOld ? aOld->GetImageRequestURLValue() : nullptr;
auto* url = GetImageRequestURLValue();
// We could avoid this const_cast generating more code but it's not really
// worth it.
const_cast<StyleComputedImageUrl*>(url)->ResolveImage(aDoc, old);
}
// --------------------
@ -1986,13 +1852,9 @@ nsStyleImageLayers::nsStyleImageLayers(const nsStyleImageLayers& aSource)
}
}
static bool IsElementImage(const nsStyleImageLayers::Layer& aLayer) {
return aLayer.mImage.GetType() == eStyleImageType_Element;
}
static bool AnyLayerIsElementImage(const nsStyleImageLayers& aLayers) {
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, aLayers) {
if (IsElementImage(aLayers.mLayers[i])) {
if (aLayers.mLayers[i].mImage.IsElement()) {
return true;
}
}
@ -2025,8 +1887,8 @@ nsChangeHint nsStyleImageLayers::CalcDifference(
const Layer& lessLayersLayer = lessLayers.mLayers[i];
nsChangeHint layerDifference =
moreLayersLayer.CalcDifference(lessLayersLayer);
if (layerDifference && (IsElementImage(moreLayersLayer) ||
IsElementImage(lessLayersLayer))) {
if (layerDifference && (moreLayersLayer.mImage.IsElement() ||
lessLayersLayer.mImage.IsElement())) {
layerDifference |=
nsChangeHint_UpdateEffects | nsChangeHint_RepaintFrame;
}
@ -2044,8 +1906,8 @@ nsChangeHint nsStyleImageLayers::CalcDifference(
}
const Layer& lessLayersLayer = lessLayers.mLayers[i];
MOZ_ASSERT(moreLayersLayer.mImage.GetType() == eStyleImageType_Null);
MOZ_ASSERT(lessLayersLayer.mImage.GetType() == eStyleImageType_Null);
MOZ_ASSERT(moreLayersLayer.mImage.IsNone());
MOZ_ASSERT(lessLayersLayer.mImage.IsNone());
if (moreLayersLayer.CalcDifference(lessLayersLayer)) {
// We don't care about the difference returned, we know it's not visible,
// but if something changed, then we need to return the neutral change.
@ -2182,9 +2044,8 @@ bool nsStyleImageLayers::IsInitialPositionForLayerType(Position aPosition,
}
static bool SizeDependsOnPositioningAreaSize(const StyleBackgroundSize& aSize,
const nsStyleImage& aImage) {
MOZ_ASSERT(aImage.GetType() != eStyleImageType_Null,
"caller should have handled this");
const StyleImage& aImage) {
MOZ_ASSERT(!aImage.IsNone(), "caller should have handled this");
// Contain and cover straightforwardly depend on frame size.
if (aSize.IsCover() || aSize.IsContain()) {
@ -2205,27 +2066,24 @@ static bool SizeDependsOnPositioningAreaSize(const StyleBackgroundSize& aSize,
return false;
}
nsStyleImageType type = aImage.GetType();
// Gradient rendering depends on frame size when auto is involved because
// gradients have no intrinsic ratio or dimensions, and therefore the relevant
// dimension is "treat[ed] as 100%".
if (type == eStyleImageType_Gradient) {
if (aImage.IsGradient()) {
return true;
}
// XXX Element rendering for auto or fixed length doesn't depend on frame size
// according to the spec. However, we don't implement the spec yet, so
// for now we bail and say element() plus auto affects ultimate size.
if (type == eStyleImageType_Element) {
if (aImage.IsElement()) {
return true;
}
if (type == eStyleImageType_Image) {
MOZ_ASSERT(aImage.IsImageRequestType(), "Missed some image");
if (auto* request = aImage.GetImageRequest()) {
nsCOMPtr<imgIContainer> imgContainer;
if (imgRequestProxy* req = aImage.GetImageData()) {
req->GetImage(getter_AddRefs(imgContainer));
}
request->GetImage(getter_AddRefs(imgContainer));
if (imgContainer) {
CSSIntSize imageSize;
AspectRatio imageRatio;
@ -2250,8 +2108,6 @@ static bool SizeDependsOnPositioningAreaSize(const StyleBackgroundSize& aSize,
return !(hasWidth && size.width.IsLengthPercentage()) &&
!(hasHeight && size.height.IsLengthPercentage());
}
} else {
MOZ_ASSERT_UNREACHABLE("missed an enum value");
}
// Passed the gauntlet: no dependency.
@ -2259,14 +2115,15 @@ static bool SizeDependsOnPositioningAreaSize(const StyleBackgroundSize& aSize,
}
nsStyleImageLayers::Layer::Layer()
: mSize(StyleBackgroundSize::ExplicitSize(LengthPercentageOrAuto::Auto(),
: mImage(StyleImage::None()),
mSize(StyleBackgroundSize::ExplicitSize(LengthPercentageOrAuto::Auto(),
LengthPercentageOrAuto::Auto())),
mClip(StyleGeometryBox::BorderBox),
mAttachment(StyleImageLayerAttachment::Scroll),
mBlendMode(NS_STYLE_BLEND_NORMAL),
mComposite(NS_STYLE_MASK_COMPOSITE_ADD),
mMaskMode(StyleMaskMode::MatchSource) {
mImage.SetNull();
}
nsStyleImageLayers::Layer::~Layer() {}
@ -2288,7 +2145,7 @@ void nsStyleImageLayers::Layer::Initialize(
bool nsStyleImageLayers::Layer::
RenderingMightDependOnPositioningAreaSizeChange() const {
// Do we even have an image?
if (mImage.IsEmpty()) {
if (mImage.IsNone()) {
return false;
}
@ -2352,10 +2209,10 @@ void nsStyleImageLayers::FillAllLayers(uint32_t aMaxItemCount) {
FillImageLayerList(mLayers, &Layer::mComposite, mCompositeCount, fillCount);
}
static bool UrlValuesEqual(const nsStyleImage& aImage,
const nsStyleImage& aOtherImage) {
auto* url = aImage.GetURLValue();
auto* other = aOtherImage.GetURLValue();
static bool UrlValuesEqual(const StyleImage& aImage,
const StyleImage& aOtherImage) {
auto* url = aImage.GetImageRequestURLValue();
auto* other = aOtherImage.GetImageRequestURLValue();
return url == other || (url && other && *url == *other);
}
@ -2419,7 +2276,7 @@ bool nsStyleBackground::HasFixedBackground(nsIFrame* aFrame) const {
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, mImage) {
const nsStyleImageLayers::Layer& layer = mImage.mLayers[i];
if (layer.mAttachment == StyleImageLayerAttachment::Fixed &&
!layer.mImage.IsEmpty() && !nsLayoutUtils::IsTransformed(aFrame)) {
!layer.mImage.IsNone() && !nsLayoutUtils::IsTransformed(aFrame)) {
return true;
}
}
@ -2439,7 +2296,7 @@ bool nsStyleBackground::IsTransparent(const nsIFrame* aFrame) const {
}
bool nsStyleBackground::IsTransparent(mozilla::ComputedStyle* aStyle) const {
return BottomLayer().mImage.IsEmpty() && mImage.mImageCount == 1 &&
return BottomLayer().mImage.IsNone() && mImage.mImageCount == 1 &&
NS_GET_A(BackgroundColor(aStyle)) == 0;
}

View File

@ -132,13 +132,6 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleFont {
RefPtr<nsAtom> mLanguage;
};
enum nsStyleImageType {
eStyleImageType_Null,
eStyleImageType_Image,
eStyleImageType_Gradient,
eStyleImageType_Element,
};
// TODO(emilio, bug 1564526): Evaluate whether this is still needed.
struct CachedBorderImageData {
~CachedBorderImageData() { PurgeCachedImages(); }
@ -177,144 +170,6 @@ struct CachedBorderImageData {
nsTArray<RefPtr<imgIContainer>> mSubImages;
};
/**
* Represents a paintable image of one of the following types.
* (1) A real image loaded from an external source.
* (2) A CSS linear or radial gradient.
* (3) An element within a document, or an <img>, <video>, or <canvas> element
* not in a document.
* (*) Optionally a crop rect can be set to paint a partial (rectangular)
* region of an image. (Currently, this feature is only supported with an
* image of type (1)).
*/
struct nsStyleImage {
using CropRect = mozilla::StyleRect<mozilla::StyleNumberOrPercentage>;
nsStyleImage();
~nsStyleImage();
nsStyleImage(const nsStyleImage& aOther);
nsStyleImage& operator=(const nsStyleImage& aOther);
void SetNull();
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) {
if (mType == eStyleImageType_Image && !mImage.IsImageResolved()) {
const auto* oldRequest =
(aOldImage && aOldImage->GetType() == eStyleImageType_Image)
? &aOldImage->ImageUrl()
: nullptr;
mImage.ResolveImage(aDocument, oldRequest);
}
}
nsStyleImageType GetType() const { return mType; }
const mozilla::StyleComputedImageUrl& ImageUrl() const {
MOZ_ASSERT(mType == eStyleImageType_Image, "Data is not an image!");
return mImage;
}
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 || ImageUrl().IsImageResolved();
}
const nsAtom* GetElementId() const {
NS_ASSERTION(mType == eStyleImageType_Element, "Data is not an element!");
return mElementId;
}
const CropRect* GetCropRect() const {
NS_ASSERTION(mType == eStyleImageType_Image,
"Only image data can have a crop rect");
return mCropRect.get();
}
already_AddRefed<nsIURI> GetImageURI() const;
const mozilla::StyleComputedImageUrl* GetURLValue() const;
/**
* Compute the actual crop rect in pixels, using the source image bounds.
* The computation involves converting percentage unit to pixel unit and
* clamping each side value to fit in the source image bounds.
* @param aActualCropRect the computed actual crop rect.
* @param aIsEntireImage true iff |aActualCropRect| is identical to the
* source image bounds.
* @return true iff |aActualCropRect| holds a meaningful value.
*/
bool ComputeActualCropRect(nsIntRect& aActualCropRect,
bool* aIsEntireImage = nullptr) const;
/**
* Starts the decoding of a image. Returns true if the current frame of the
* image is complete. The return value is intended to be used instead of
* IsComplete because IsComplete may not be up to date if notifications
* from decoding are pending because they are being sent async.
*/
bool StartDecoding() const;
/**
* @return true if the item is definitely opaque --- i.e., paints every
* pixel within its bounds opaquely, and the bounds contains at least a pixel.
*/
bool IsOpaque() const;
/**
* @return true if this image is fully loaded, and its size is calculated;
* always returns true if |mType| is |eStyleImageType_Gradient| or
* |eStyleImageType_Element|.
*/
bool IsComplete() const;
/**
* @return true if this image has an available size, and hasn't errored.
* always returns true if |mType| is |eStyleImageType_Gradient| or
* |eStyleImageType_Element|.
*/
bool IsSizeAvailable() const;
/**
* @return true if it is 100% confident that this image contains no pixel
* to draw.
*/
bool IsEmpty() const {
// There are some other cases when the image will be empty, for example
// when the crop rect is empty. However, checking the emptiness of crop
// rect is non-trivial since each side value can be specified with
// percentage unit, which can not be evaluated until the source image size
// is available. Therefore, we currently postpone the evaluation of crop
// rect until the actual rendering time --- alternatively until
// GetOpaqueRegion() is called.
return mType == eStyleImageType_Null;
}
bool operator==(const nsStyleImage& aOther) const;
bool operator!=(const nsStyleImage& aOther) const {
return !(*this == aOther);
}
bool ImageDataEquals(const nsStyleImage& aOther) const {
return GetType() == eStyleImageType_Image &&
aOther.GetType() == eStyleImageType_Image &&
GetImageData() == aOther.GetImageData();
}
private:
void DoCopy(const nsStyleImage& aOther);
// This is _currently_ used only in conjunction with eStyleImageType_Image.
mozilla::UniquePtr<CropRect> mCropRect;
nsStyleImageType mType;
union {
mozilla::StyleComputedImageUrl mImage;
mozilla::StyleGradient* mGradient;
nsAtom* mElementId;
};
};
struct nsStyleImageLayers {
// Indices into kBackgroundLayerTable and kMaskLayerTable
enum {
@ -374,7 +229,7 @@ struct nsStyleImageLayers {
typedef mozilla::StyleImageLayerAttachment StyleImageLayerAttachment;
typedef mozilla::StyleBackgroundSize StyleBackgroundSize;
nsStyleImage mImage;
mozilla::StyleImage mImage;
mozilla::Position mPosition;
StyleBackgroundSize mSize;
StyleGeometryBox mClip;
@ -653,7 +508,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleBorder {
bool HasBorder() const {
return mComputedBorder != nsMargin(0, 0, 0, 0) ||
!mBorderImageSource.IsEmpty();
!mBorderImageSource.IsNone();
}
// Get the actual border width for a particular side, in appunits. Note that
@ -683,15 +538,12 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleBorder {
nsMargin GetImageOutset() const;
imgIRequest* GetBorderImageRequest() const {
if (mBorderImageSource.GetType() == eStyleImageType_Image) {
return mBorderImageSource.GetImageData();
}
return nullptr;
return mBorderImageSource.GetImageRequest();
}
public:
mozilla::StyleBorderRadius mBorderRadius; // coord, percent
nsStyleImage mBorderImageSource;
mozilla::StyleImage mBorderImageSource;
mozilla::StyleBorderImageWidth mBorderImageWidth;
mozilla::StyleNonNegativeLengthOrNumberRect mBorderImageOutset;
mozilla::StyleBorderImageSlice mBorderImageSlice; // factor, percent
@ -1317,7 +1169,7 @@ struct StyleShapeSource final {
StyleShapeSourceType GetType() const { return mType; }
const nsStyleImage& ShapeImage() const {
const StyleImage& ShapeImage() const {
MOZ_ASSERT(mType == StyleShapeSourceType::Image,
"Wrong shape source type!");
MOZ_ASSERT(mShapeImage);
@ -1329,9 +1181,9 @@ struct StyleShapeSource final {
// null.
imgIRequest* GetShapeImageData() const;
void SetShapeImage(UniquePtr<nsStyleImage> aShapeImage);
void SetShapeImage(UniquePtr<StyleImage> aShapeImage);
const mozilla::StyleBasicShape& BasicShape() const {
const StyleBasicShape& BasicShape() const {
MOZ_ASSERT(mType == StyleShapeSourceType::Shape,
"Wrong shape source type!");
MOZ_ASSERT(mBasicShape);
@ -1367,9 +1219,9 @@ struct StyleShapeSource final {
void DoDestroy();
union {
mozilla::UniquePtr<mozilla::StyleBasicShape> mBasicShape;
mozilla::UniquePtr<nsStyleImage> mShapeImage;
mozilla::UniquePtr<StyleSVGPath> mSVGPath;
UniquePtr<StyleBasicShape> mBasicShape;
UniquePtr<StyleImage> mShapeImage;
UniquePtr<StyleSVGPath> mSVGPath;
// TODO: Bug 1480665, implement ray() function.
};
StyleShapeSourceType mType = StyleShapeSourceType::None;

View File

@ -199,7 +199,7 @@ mozilla::StylePointerEvents nsStyleUI::GetEffectivePointerEvents(
bool nsStyleBackground::HasLocalBackground() const {
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, mImage) {
const nsStyleImageLayers::Layer& layer = mImage.mLayers[i];
if (!layer.mImage.IsEmpty() &&
if (!layer.mImage.IsNone() &&
layer.mAttachment == mozilla::StyleImageLayerAttachment::Local) {
return true;
}

View File

@ -849,7 +849,7 @@ SVGMaskObserverList::SVGMaskObserverList(nsIFrame* aFrame) : mFrame(aFrame) {
for (uint32_t i = 0; i < svgReset->mMask.mImageCount; i++) {
const StyleComputedImageUrl* data =
svgReset->mMask.mLayers[i].mImage.GetURLValue();
svgReset->mMask.mLayers[i].mImage.GetImageRequestURLValue();
RefPtr<URLAndReferrerInfo> maskUri;
if (data) {
maskUri = ResolveURLUsingLocalRef(aFrame, *data);
@ -876,17 +876,16 @@ void SVGMaskObserverList::ResolveImage(uint32_t aIndex) {
const nsStyleSVGReset* svgReset = mFrame->StyleSVGReset();
MOZ_ASSERT(aIndex < svgReset->mMask.mImageCount);
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);
Document* doc = mFrame->PresContext()->Document();
if (imgRequestProxy* req = image.GetImageData()) {
doc->StyleImageLoader()->AssociateRequestToFrame(req, mFrame, 0);
}
auto& image = const_cast<StyleImage&>(svgReset->mMask.mLayers[aIndex].mImage);
if (image.IsResolved()) {
return;
}
MOZ_ASSERT(image.IsImageRequestType());
Document* doc = mFrame->PresContext()->Document();
image.ResolveImage(*doc, nullptr);
if (imgRequestProxy* req = image.GetImageRequest()) {
// FIXME(emilio): What disassociates this request?
doc->StyleImageLoader()->AssociateRequestToFrame(req, mFrame, 0);
}
}
@ -1265,8 +1264,9 @@ static nsSVGPaintingProperty* GetOrCreateClipPathObserver(
if (svgStyleReset->mClipPath.GetType() != StyleShapeSourceType::Image) {
return nullptr;
}
const auto* url = svgStyleReset->mClipPath.ShapeImage().GetURLValue();
MOZ_ASSERT(url);
const auto* url =
svgStyleReset->mClipPath.ShapeImage().GetImageRequestURLValue();
MOZ_ASSERT(url, "Clip-path only supports url() images");
RefPtr<URLAndReferrerInfo> pathURI =
ResolveURLUsingLocalRef(aClippedFrame, *url);
return GetPaintingProperty(pathURI, aClippedFrame, ClipPathProperty());

View File

@ -10,87 +10,10 @@
#![allow(unsafe_code)]
use crate::gecko_bindings::bindings;
use crate::gecko_bindings::structs::{self, Matrix4x4Components};
use crate::gecko_bindings::structs::{nsStyleImage, nsresult};
use crate::gecko_bindings::structs::{self, Matrix4x4Components, nsresult};
use crate::stylesheets::RulesMutateError;
use crate::values::computed::transform::Matrix3D;
use crate::values::computed::{Gradient, Image, TextAlign};
use crate::values::generics::image::GenericImage;
use crate::values::generics::rect::Rect;
impl nsStyleImage {
/// Set a given Servo `Image` value into this `nsStyleImage`.
pub fn set(&mut self, image: Image) {
match image {
GenericImage::None => unsafe {
bindings::Gecko_SetNullImageValue(self);
},
GenericImage::Gradient(boxed_gradient) => self.set_gradient(boxed_gradient),
GenericImage::Url(ref url) => unsafe {
bindings::Gecko_SetLayerImageImageValue(self, url);
},
GenericImage::Rect(ref image_rect) => {
unsafe {
bindings::Gecko_SetLayerImageImageValue(self, &image_rect.url);
bindings::Gecko_InitializeImageCropRect(self);
// Set CropRect
let ref mut rect = *self.mCropRect.mPtr;
*rect = Rect(
image_rect.top,
image_rect.right,
image_rect.bottom,
image_rect.left,
);
}
},
GenericImage::Element(ref element) => unsafe {
bindings::Gecko_SetImageElement(self, element.as_ptr());
},
}
}
fn set_gradient(&mut self, gradient: Box<Gradient>) {
unsafe {
bindings::Gecko_SetGradientImageValue(self, Box::into_raw(gradient));
}
}
/// Converts into Image.
pub unsafe fn to_image(&self) -> Image {
use crate::gecko_bindings::structs::nsStyleImageType;
use crate::values::computed::MozImageRect;
match self.mType {
nsStyleImageType::eStyleImageType_Null => GenericImage::None,
nsStyleImageType::eStyleImageType_Image => {
let url = self.__bindgen_anon_1.mImage.as_ref().clone();
if self.mCropRect.mPtr.is_null() {
GenericImage::Url(url)
} else {
let rect = &*self.mCropRect.mPtr;
GenericImage::Rect(Box::new(MozImageRect {
url,
top: rect.0,
right: rect.1,
bottom: rect.2,
left: rect.3,
}))
}
},
nsStyleImageType::eStyleImageType_Gradient => {
let gradient: &Gradient = &**self.__bindgen_anon_1.mGradient.as_ref();
GenericImage::Gradient(Box::new(gradient.clone()))
},
nsStyleImageType::eStyleImageType_Element => {
use crate::gecko_string_cache::Atom;
let atom = bindings::Gecko_GetImageElement(self);
GenericImage::Element(Atom::from_raw(atom))
},
}
}
}
use crate::values::computed::TextAlign;
pub mod basic_shape {
//! Conversions from and to CSS shape representations.
@ -148,9 +71,8 @@ pub mod basic_shape {
use crate::values::generics::image::Image as GenericImage;
let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr;
let image = shape_image.to_image();
match image {
GenericImage::Url(url) => ShapeSource::ImageOrUrl(url.0),
match *shape_image {
GenericImage::Url(ref url) => ShapeSource::ImageOrUrl(url.0.clone()),
_ => panic!("ClippingShape doesn't support non-url images"),
}
},
@ -166,8 +88,7 @@ pub mod basic_shape {
match other.mType {
StyleShapeSourceType::Image => unsafe {
let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr;
let image = shape_image.to_image();
ShapeSource::ImageOrUrl(image)
ShapeSource::ImageOrUrl(shape_image.clone())
},
_ => other
.to_shape_source()

View File

@ -24,11 +24,9 @@ use crate::gecko_bindings::bindings::Gecko_Destroy_${style_struct.gecko_ffi_name
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_EnsureImageLayersLength;
use crate::gecko_bindings::bindings::Gecko_nsStyleFont_SetLang;
use crate::gecko_bindings::bindings::Gecko_nsStyleFont_CopyLangFrom;
use crate::gecko_bindings::bindings::Gecko_SetNullImageValue;
use crate::gecko_bindings::structs;
use crate::gecko_bindings::structs::nsCSSPropertyID;
use crate::gecko_bindings::structs::mozilla::PseudoStyleType;
@ -777,8 +775,7 @@ fn static_assert() {
for x in CORNERS]) %>
<%self:impl_trait style_struct_name="Border"
skip_longhands="${skip_border_longhands} border-image-source
border-image-repeat">
skip_longhands="${skip_border_longhands} border-image-repeat">
% for side in SIDES:
pub fn set_border_${side.ident}_style(&mut self, v: BorderStyle) {
self.gecko.mBorderStyle[${side.index}] = v;
@ -847,25 +844,6 @@ fn static_assert() {
corner) %>
% endfor
pub fn set_border_image_source(&mut self, image: longhands::border_image_source::computed_value::T) {
self.gecko.mBorderImageSource.set(image);
}
pub fn copy_border_image_source_from(&mut self, other: &Self) {
unsafe {
Gecko_CopyImageValueFrom(&mut self.gecko.mBorderImageSource,
&other.gecko.mBorderImageSource);
}
}
pub fn reset_border_image_source(&mut self, other: &Self) {
self.copy_border_image_source_from(other)
}
pub fn clone_border_image_source(&self) -> longhands::border_image_source::computed_value::T {
unsafe { self.gecko.mBorderImageSource.to_image() }
}
<%
border_image_repeat_keywords = ["Stretch", "Repeat", "Round", "Space"]
%>
@ -1998,7 +1976,7 @@ fn static_assert() {
for (layer, other) in self.gecko.${image_layers_field}.mLayers.iter_mut()
.zip(other.gecko.${image_layers_field}.mLayers.iter())
.take(count as usize) {
Gecko_CopyImageValueFrom(&mut layer.mImage, &other.mImage);
layer.mImage = other.mImage.clone();
}
self.gecko.${image_layers_field}.mImageCount = count;
}
@ -2018,20 +1996,17 @@ fn static_assert() {
let images = images.into_iter();
unsafe {
// Prevent leaking of the last elements we did set
for image in &mut self.gecko.${image_layers_field}.mLayers {
Gecko_SetNullImageValue(&mut image.mImage)
}
// XXXManishearth clear mSourceURI for masks
Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field}, images.len(),
LayerType::${shorthand.title()});
Gecko_EnsureImageLayersLength(
&mut self.gecko.${image_layers_field},
images.len(),
LayerType::${shorthand.title()},
);
}
self.gecko.${image_layers_field}.mImageCount = images.len() as u32;
for (image, geckoimage) in images.zip(self.gecko.${image_layers_field}
.mLayers.iter_mut()) {
geckoimage.mImage.set(image)
geckoimage.mImage = image;
}
}
@ -2039,7 +2014,7 @@ fn static_assert() {
longhands::${shorthand}_image::computed_value::List(
self.gecko.${image_layers_field}.mLayers.iter()
.take(self.gecko.${image_layers_field}.mImageCount as usize)
.map(|layer| unsafe { layer.mImage.to_image() })
.map(|layer| layer.mImage.clone())
.collect()
)
}
@ -2266,7 +2241,7 @@ fn set_style_svg_path(
unsafe {
bindings::Gecko_NewShapeImage(${ident});
let style_image = &mut *${ident}.__bindgen_anon_1.mShapeImage.as_mut().mPtr;
style_image.set(image);
*style_image = image;
}
}
ShapeSource::Box(reference) => {

View File

@ -703,31 +703,76 @@ renaming_overrides_prefixing = true
"""
"GenericRotate" = """
public:
public:
// The implementation of IPC LayersMessages needs this to be public.
StyleGenericRotate(): tag(Tag::None) {}
"""
"GenericScale" = """
public:
public:
// The implementation of IPC LayersMessages needs this to be public.
StyleGenericScale(): tag(Tag::None) {}
"""
"GenericTranslate" = """
public:
public:
// The implementation of IPC LayersMessages needs this to be public.
StyleGenericTranslate(): tag(Tag::None) {}
"""
"GenericOffsetPath" = """
public:
public:
// The implementation of IPC LayersMessages needs this to be public.
StyleGenericOffsetPath(): tag(Tag::None) {}
"""
"GenericPositionOrAuto" = """
public:
public:
// The implementation of IPC LayersMessages needs this to be public.
StyleGenericPositionOrAuto(): tag(Tag::Auto) {}
"""
"GenericImage" = """
public:
// Whether this image may have an image request associated with it.
bool IsImageRequestType() const;
// Gets the image request URL.
const StyleComputedImageUrl* GetImageRequestURLValue() const;
// Gets the image data of this image if it has any image request.
imgRequestProxy* GetImageRequest() const;
// Returns true if this image is fully loaded, and its size is calculated.
// Always returns true if there's no image request involved and this image
// is not `none`.
bool IsComplete() const;
// Returns true if this image has an available size and hasn't errored.
// Always returns true if there's no image request involved and this image
// is not `none`.
bool IsSizeAvailable() const;
// Starts the decoding of a image. Returns true if the current frame of the
// image is complete. The return value is intended to be used instead of
// IsComplete because IsComplete may not be up to date if notifications
// from decoding are pending because they are being sent async.
bool StartDecoding() const;
// Returns true if the item is definitely opaque --- i.e., paints every
// pixel within its bounds opaquely, and the bounds contains at least a pixel.
bool IsOpaque() const;
struct ActualCropRect {
nsIntRect mRect; // in image pixels
bool mIsEntireImage;
};
Maybe<ActualCropRect> ComputeActualCropRect() const;
// Resolves the underlying image request if any.
void ResolveImage(dom::Document&, const StyleGenericImage* aOld);
// Returns whether this image has been resolved.
bool IsResolved() const;
"""