From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- layout/painting/nsImageRenderer.cpp | 1054 +++++++++++++++++++++++++++++++++++ 1 file changed, 1054 insertions(+) create mode 100644 layout/painting/nsImageRenderer.cpp (limited to 'layout/painting/nsImageRenderer.cpp') diff --git a/layout/painting/nsImageRenderer.cpp b/layout/painting/nsImageRenderer.cpp new file mode 100644 index 0000000000..d2fa024d4d --- /dev/null +++ b/layout/painting/nsImageRenderer.cpp @@ -0,0 +1,1054 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* utility code for drawing images as CSS borders, backgrounds, and shapes. */ + +#include "nsImageRenderer.h" + +#include "mozilla/webrender/WebRenderAPI.h" + +#include "gfxContext.h" +#include "gfxDrawable.h" +#include "ImageOps.h" +#include "ImageRegion.h" +#include "mozilla/image/WebRenderImageProvider.h" +#include "mozilla/layers/RenderRootStateManager.h" +#include "mozilla/layers/StackingContextHelper.h" +#include "mozilla/layers/WebRenderLayerManager.h" +#include "nsContentUtils.h" +#include "nsCSSRendering.h" +#include "nsCSSRenderingGradients.h" +#include "nsDeviceContext.h" +#include "nsIFrame.h" +#include "nsLayoutUtils.h" +#include "nsStyleStructInlines.h" +#include "mozilla/StaticPrefs_image.h" +#include "mozilla/ISVGDisplayableFrame.h" +#include "mozilla/SVGIntegrationUtils.h" +#include "mozilla/SVGPaintServerFrame.h" +#include "mozilla/SVGObserverUtils.h" + +using namespace mozilla; +using namespace mozilla::gfx; +using namespace mozilla::image; +using namespace mozilla::layers; + +nsSize CSSSizeOrRatio::ComputeConcreteSize() const { + NS_ASSERTION(CanComputeConcreteSize(), "Cannot compute"); + if (mHasWidth && mHasHeight) { + return nsSize(mWidth, mHeight); + } + if (mHasWidth) { + return nsSize(mWidth, mRatio.Inverted().ApplyTo(mWidth)); + } + + MOZ_ASSERT(mHasHeight); + return nsSize(mRatio.ApplyTo(mHeight), mHeight); +} + +nsImageRenderer::nsImageRenderer(nsIFrame* aForFrame, const StyleImage* aImage, + uint32_t aFlags) + : mForFrame(aForFrame), + mImage(&aImage->FinalImage()), + mImageResolution(aImage->GetResolution()), + mType(mImage->tag), + mImageContainer(nullptr), + mGradientData(nullptr), + mPaintServerFrame(nullptr), + mPrepareResult(ImgDrawResult::NOT_READY), + mSize(0, 0), + mFlags(aFlags), + mExtendMode(ExtendMode::CLAMP), + mMaskOp(StyleMaskMode::MatchSource) {} + +bool nsImageRenderer::PrepareImage() { + if (mImage->IsNone()) { + mPrepareResult = ImgDrawResult::BAD_IMAGE; + return false; + } + + const bool isImageRequest = mImage->IsImageRequestType(); + MOZ_ASSERT_IF(!isImageRequest, !mImage->GetImageRequest()); + imgRequestProxy* request = nullptr; + if (isImageRequest) { + request = mImage->GetImageRequest(); + if (!request) { + // request 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; + } + } + + if (!mImage->IsComplete()) { + MOZ_DIAGNOSTIC_ASSERT(isImageRequest); + + // Make sure the image is actually decoding. + bool frameComplete = request->StartDecodingWithResult( + imgIContainer::FLAG_ASYNC_NOTIFY | + imgIContainer::FLAG_AVOID_REDECODE_FOR_SIZE); + + // Boost the loading priority since we know we want to draw the image. + if (mFlags & nsImageRenderer::FLAG_PAINTING_TO_WINDOW) { + request->BoostPriority(imgIRequest::CATEGORY_DISPLAY); + } + + // Check again to see if we finished. + // We cannot prepare the image for rendering if it is not fully loaded. + if (!frameComplete && !mImage->IsComplete()) { + uint32_t imageStatus = 0; + request->GetImageStatus(&imageStatus); + if (imageStatus & imgIRequest::STATUS_ERROR) { + mPrepareResult = ImgDrawResult::BAD_IMAGE; + return false; + } + + // If not errored, and we requested a sync decode, and the image has + // loaded, push on through because the Draw() will do a sync decode then. + const bool syncDecodeWillComplete = + (mFlags & FLAG_SYNC_DECODE_IMAGES) && + (imageStatus & imgIRequest::STATUS_LOAD_COMPLETE); + + bool canDrawPartial = + (mFlags & nsImageRenderer::FLAG_DRAW_PARTIAL_FRAMES) && + isImageRequest && mImage->IsSizeAvailable() && !mImage->IsRect(); + + // If we are drawing a partial frame then we want to make sure there are + // some pixels to draw, otherwise we waste effort pushing through to draw + // nothing. + if (!syncDecodeWillComplete && canDrawPartial) { + nsCOMPtr image; + canDrawPartial = + canDrawPartial && + NS_SUCCEEDED(request->GetImage(getter_AddRefs(image))) && image && + image->GetType() == imgIContainer::TYPE_RASTER && + image->HasDecodedPixels(); + } + + // If we can draw partial then proceed if we at least have the size + // available. + if (!(syncDecodeWillComplete || canDrawPartial)) { + mPrepareResult = ImgDrawResult::NOT_READY; + return false; + } + } + } + + if (isImageRequest) { + nsCOMPtr srcImage; + nsresult rv = request->GetImage(getter_AddRefs(srcImage)); + MOZ_ASSERT(NS_SUCCEEDED(rv) && srcImage, + "If GetImage() is failing, mImage->IsComplete() " + "should have returned false"); + if (!NS_SUCCEEDED(rv)) { + srcImage = nullptr; + } + + if (srcImage) { + StyleImageOrientation orientation = + mForFrame->StyleVisibility()->UsedImageOrientation(request); + srcImage = nsLayoutUtils::OrientImage(srcImage, orientation); + } + + 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 { + nsCOMPtr subImage = + ImageOps::Clip(srcImage, croprect->mRect, Nothing()); + mImageContainer.swap(subImage); + } + } + 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 , , or