Skip to content

Commit

Permalink
Cherry-pick 265870.5@safari-7616-branch (a06556a). https://bugs.webki…
Browse files Browse the repository at this point in the history
…t.org/show_bug.cgi?id=258712

    Crash under SVGImageChromeClient::invalidateContentsAndRootView()
    https://bugs.webkit.org/show_bug.cgi?id=258992
    rdar://111456803

    Reviewed by David Kilzer.

    Do hardening by deploying WeakPtr instead of raw pointers for
    SVGImage and ImageObserver. Also make it so that we can ref
    an ImageObserver.

    * Source/WebCore/html/ImageBitmap.cpp:
    * Source/WebCore/html/canvas/CanvasRenderingContext2DBase.cpp:
    (WebCore::CanvasRenderingContext2DBase::drawImage):
    * Source/WebCore/loader/cache/CachedImage.h:
    * Source/WebCore/platform/graphics/BitmapImage.cpp:
    (WebCore::BitmapImage::draw):
    (WebCore::BitmapImage::drawPattern):
    (WebCore::BitmapImage::internalAdvanceAnimation):
    (WebCore::BitmapImage::imageFrameAvailableAtIndex):
    * Source/WebCore/platform/graphics/GraphicsContextGL.cpp:
    (WebCore::GraphicsContextGL::packImageData):
    * Source/WebCore/platform/graphics/Image.cpp:
    (WebCore::Image::imageObserver const):
    (WebCore::Image::setImageObserver):
    (WebCore::Image::drawPattern):
    * Source/WebCore/platform/graphics/Image.h:
    (WebCore::Image::imageObserver const): Deleted.
    (WebCore::Image::setImageObserver): Deleted.
    * Source/WebCore/platform/graphics/ImageObserver.h:
    (WebCore::ImageObserver::ref):
    (WebCore::ImageObserver::deref):
    * Source/WebCore/platform/graphics/ImageSource.cpp:
    (WebCore::ImageSource::encodedDataStatusChanged):
    (WebCore::ImageSource::decodedSizeChanged):
    * Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp:
    (WebCore::PDFDocumentImage::decodedSizeChanged):
    (WebCore::PDFDocumentImage::draw):
    * Source/WebCore/platform/graphics/texmap/TextureMapperTiledBackingStore.cpp:
    (WebCore::TextureMapperTiledBackingStore::updateContentsFromImageIfNeeded):
    * Source/WebCore/svg/graphics/SVGImage.cpp:
    (WebCore::SVGImage::drawForContainer):
    (WebCore::SVGImage::nativeImage):
    (WebCore::SVGImage::draw):
    (WebCore::SVGImage::dataChanged):
    * Source/WebCore/svg/graphics/SVGImageClients.h:
    * Tools/TestWebKitAPI/Tests/WebCore/SVGImageCasts.cpp:
    (TestWebKitAPI::TestImageObserver::create):
    (TestWebKitAPI::TEST):

    Canonical link: https://commits.webkit.org/265870.5@safari-7616-branch
  • Loading branch information
cdumez authored and mcatanzaro committed Sep 26, 2023
1 parent 2a769cb commit 5507f06
Show file tree
Hide file tree
Showing 14 changed files with 82 additions and 49 deletions.
2 changes: 1 addition & 1 deletion Source/WebCore/html/ImageBitmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,7 @@ void ImageBitmap::createCompletionHandler(ScriptExecutionContext& scriptExecutio
completionHandler(WTFMove(imageBitmap));
}

class ImageBitmapImageObserver final : public RefCounted<ImageBitmapImageObserver>, public ImageObserver {
class ImageBitmapImageObserver final : public ImageObserver {
public:
static Ref<ImageBitmapImageObserver> create(String mimeType, long long expectedContentLength, const URL& sourceUrl)
{
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/html/canvas/CanvasRenderingContext2DBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1637,7 +1637,7 @@ ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(Document& document, Ca
if (!image)
return { };

ImageObserver* observer = image->imageObserver();
auto observer = image->imageObserver();

if (image->drawsSVGImage()) {
image->setImageObserver(nullptr);
Expand Down Expand Up @@ -1673,7 +1673,7 @@ ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(Document& document, Ca
didDraw(repaintEntireCanvas, normalizedDstRect);

if (image->drawsSVGImage())
image->setImageObserver(observer);
image->setImageObserver(WTFMove(observer));

return { };
}
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/loader/cache/CachedImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ class CachedImage final : public CachedResource {
// For compatibility, images keep loading even if there are HTTP errors.
bool shouldIgnoreHTTPStatusCodeErrors() const override { return true; }

class CachedImageObserver final : public RefCounted<CachedImageObserver>, public ImageObserver {
class CachedImageObserver final : public ImageObserver {
public:
static Ref<CachedImageObserver> create(CachedImage& image) { return adoptRef(*new CachedImageObserver(image)); }
WeakHashSet<CachedImage>& cachedImages() { return m_cachedImages; }
Expand Down
16 changes: 8 additions & 8 deletions Source/WebCore/platform/graphics/BitmapImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,8 @@ ImageDrawResult BitmapImage::draw(GraphicsContext& context, const FloatRect& des

m_currentFrameDecodingStatus = frameDecodingStatusAtIndex(m_currentFrame);

if (imageObserver())
imageObserver()->didDraw(*this);
if (auto observer = imageObserver())
observer->didDraw(*this);

return result;
}
Expand All @@ -357,14 +357,14 @@ void BitmapImage::drawPattern(GraphicsContext& ctxt, const FloatRect& destRect,
if (!buffer)
return;

ImageObserver* observer = imageObserver();
auto observer = imageObserver();

// Temporarily reset image observer, we don't want to receive any changeInRect() calls due to this relayout.
setImageObserver(nullptr);

draw(buffer->context(), tileRect, tileRect, { options, DecodingMode::Synchronous, ImageOrientation::Orientation::FromImage });

setImageObserver(observer);
setImageObserver(WTFMove(observer));
buffer->convertToLuminanceMask();

m_cachedImage = ImageBuffer::sinkIntoImage(WTFMove(buffer), PreserveResolution::Yes);
Expand Down Expand Up @@ -541,8 +541,8 @@ void BitmapImage::internalAdvanceAnimation()

callDecodingCallbacks();

if (imageObserver())
imageObserver()->imageFrameAvailable(*this, ImageAnimatingState::Yes, nullptr, decodingStatus);
if (auto observer = imageObserver())
observer->imageFrameAvailable(*this, ImageAnimatingState::Yes, nullptr, decodingStatus);

LOG(Images, "BitmapImage::%s - %p - url: %s [m_currentFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), m_currentFrame);
}
Expand Down Expand Up @@ -654,8 +654,8 @@ void BitmapImage::imageFrameAvailableAtIndex(size_t index)
if (frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, DecodingMode::Asynchronous))
callDecodingCallbacks();

if (imageObserver())
imageObserver()->imageFrameAvailable(*this, ImageAnimatingState::No, nullptr, decodingStatus);
if (auto observer = imageObserver())
observer->imageFrameAvailable(*this, ImageAnimatingState::No, nullptr, decodingStatus);
}

DestinationColorSpace BitmapImage::colorSpace()
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/platform/graphics/GraphicsContextGL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ bool GraphicsContextGL::packImageData(Image* image, const void* pixels, GCGLenum

if (!packPixels(static_cast<const uint8_t*>(pixels), sourceFormat, sourceImageWidth, sourceImageHeight, sourceImageSubRectangle, depth, sourceUnpackAlignment, unpackImageHeight, format, type, alphaOp, data.data(), flipY))
return false;
if (ImageObserver* observer = image->imageObserver())
if (auto observer = image->imageObserver())
observer->didDraw(*image);
return true;
}
Expand Down
14 changes: 12 additions & 2 deletions Source/WebCore/platform/graphics/Image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ Image::Image(ImageObserver* observer)

Image::~Image() = default;

RefPtr<ImageObserver> Image::imageObserver() const
{
return m_imageObserver.get();
}

void Image::setImageObserver(RefPtr<ImageObserver>&& observer)
{
m_imageObserver = observer.get();
}

Image& Image::nullImage()
{
ASSERT(isMainThread());
Expand Down Expand Up @@ -152,8 +162,8 @@ void Image::drawPattern(GraphicsContext& ctxt, const FloatRect& destRect, const

ctxt.drawPattern(*tileImage, destRect, tileRect, patternTransform, phase, spacing, options);

if (imageObserver())
imageObserver()->didDraw(*this);
if (auto observer = imageObserver())
observer->didDraw(*this);
}

ImageDrawResult Image::drawTiled(GraphicsContext& ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, const FloatSize& spacing, const ImagePaintingOptions& options)
Expand Down
8 changes: 4 additions & 4 deletions Source/WebCore/platform/graphics/Image.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ struct Length;
// This class gets notified when an image creates or destroys decoded frames and when it advances animation frames.
class ImageObserver;

class Image : public RefCounted<Image> {
class Image : public RefCounted<Image>, public CanMakeWeakPtr<Image> {
friend class CachedSubimage;
friend class GraphicsContext;
public:
Expand Down Expand Up @@ -153,8 +153,8 @@ class Image : public RefCounted<Image> {
void setAllowsAnimation(std::optional<bool> allowsAnimation) { m_allowsAnimation = allowsAnimation; }

// Typically the CachedImage that owns us.
ImageObserver* imageObserver() const { return m_imageObserver; }
void setImageObserver(ImageObserver* observer) { m_imageObserver = observer; }
RefPtr<ImageObserver> imageObserver() const;
void setImageObserver(RefPtr<ImageObserver>&&);
URL sourceURL() const;
WEBCORE_EXPORT String mimeType() const;
long long expectedContentLength() const;
Expand Down Expand Up @@ -216,7 +216,7 @@ class Image : public RefCounted<Image> {

private:
RefPtr<FragmentedSharedBuffer> m_encodedImageData;
ImageObserver* m_imageObserver;
WeakPtr<ImageObserver> m_imageObserver;

// A value of true or false will override the default Page::imageAnimationEnabled state.
std::optional<bool> m_allowsAnimation { std::nullopt };
Expand Down
11 changes: 8 additions & 3 deletions Source/WebCore/platform/graphics/ImageObserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
#pragma once

#include "ImageTypes.h"
#include <wtf/RefCounted.h>
#include <wtf/URL.h>
#include <wtf/WeakPtr.h>

namespace WebCore {

Expand All @@ -35,10 +37,10 @@ class IntRect;

// Interface for notification about changes to an image, including decoding,
// drawing, and animating.
class ImageObserver {
protected:
virtual ~ImageObserver() = default;
class ImageObserver : public RefCounted<ImageObserver>, public CanMakeWeakPtr<ImageObserver> {
public:
virtual ~ImageObserver() = default;

virtual URL sourceUrl() const = 0;
virtual String mimeType() const = 0;
virtual long long expectedContentLength() const = 0;
Expand All @@ -55,6 +57,9 @@ class ImageObserver {

virtual bool allowsAnimation(const Image&) const { return true; }
virtual bool layerBasedSVGEngineEnabled() const { return false; }

protected:
ImageObserver() = default;
};

}
12 changes: 8 additions & 4 deletions Source/WebCore/platform/graphics/ImageSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,16 +166,20 @@ void ImageSource::encodedDataStatusChanged(EncodedDataStatus status)
if (status >= EncodedDataStatus::SizeAvailable)
growFrames();

if (m_image && m_image->imageObserver())
m_image->imageObserver()->encodedDataStatusChanged(*m_image, status);
if (!m_image)
return;

if (auto observer = m_image->imageObserver())
observer->encodedDataStatusChanged(*m_image, status);
}

void ImageSource::decodedSizeChanged(long long decodedSize)
{
if (!decodedSize || !m_image || !m_image->imageObserver())
if (!decodedSize || !m_image)
return;

m_image->imageObserver()->decodedSizeChanged(*m_image, decodedSize);
if (auto imageObserver = m_image->imageObserver())
imageObserver->decodedSizeChanged(*m_image, decodedSize);
}

void ImageSource::decodedSizeIncreased(unsigned decodedSize)
Expand Down
8 changes: 4 additions & 4 deletions Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ void PDFDocumentImage::decodedSizeChanged(size_t newCachedBytes)
if (!m_cachedBytes && !newCachedBytes)
return;

if (imageObserver())
imageObserver()->decodedSizeChanged(*this, -static_cast<long long>(m_cachedBytes) + newCachedBytes);
if (auto observer = imageObserver())
observer->decodedSizeChanged(*this, -static_cast<long long>(m_cachedBytes) + newCachedBytes);

m_cachedBytes = newCachedBytes;
}
Expand Down Expand Up @@ -154,8 +154,8 @@ ImageDrawResult PDFDocumentImage::drawPDFDocument(GraphicsContext& context, cons
context.scale({ 1, -1 });
drawPDFPage(context);

if (imageObserver())
imageObserver()->didDraw(*this);
if (auto observer = imageObserver())
observer->didDraw(*this);

return ImageDrawResult::DidDraw;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ void TextureMapperTiledBackingStore::updateContentsFromImageIfNeeded(TextureMapp

updateContents(textureMapper, m_image.get(), m_image->size(), enclosingIntRect(m_image->rect()));

if (m_image->imageObserver())
m_image->imageObserver()->didDraw(*m_image);
if (auto observer = m_image->imageObserver())
observer->didDraw(*m_image);
m_image = nullptr;
}

Expand Down
14 changes: 7 additions & 7 deletions Source/WebCore/svg/graphics/SVGImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ ImageDrawResult SVGImage::drawForContainer(GraphicsContext& context, const Float
if (!m_page)
return ImageDrawResult::DidNothing;

ImageObserver* observer = imageObserver();
auto observer = imageObserver();
ASSERT(observer);

// Temporarily reset image observer, we don't want to receive any changeInRect() calls due to this relayout.
Expand All @@ -211,7 +211,7 @@ ImageDrawResult SVGImage::drawForContainer(GraphicsContext& context, const Float

ImageDrawResult result = draw(context, dstRect, scaledSrc, options);

setImageObserver(observer);
setImageObserver(WTFMove(observer));
return result;
}

Expand All @@ -232,13 +232,13 @@ RefPtr<NativeImage> SVGImage::nativeImage(const DestinationColorSpace& colorSpac
if (!imageBuffer)
return nullptr;

ImageObserver* observer = imageObserver();
auto observer = imageObserver();
setImageObserver(nullptr);
setContainerSize(size());

imageBuffer->context().drawImage(*this, FloatPoint(0, 0));

setImageObserver(observer);
setImageObserver(WTFMove(observer));
return ImageBuffer::sinkIntoNativeImage(WTFMove(imageBuffer));
}

Expand Down Expand Up @@ -327,8 +327,8 @@ ImageDrawResult SVGImage::draw(GraphicsContext& context, const FloatRect& dstRec

stateSaver.restore();

if (imageObserver())
imageObserver()->didDraw(*this);
if (auto observer = imageObserver())
observer->didDraw(*this);

return ImageDrawResult::DidDraw;
}
Expand Down Expand Up @@ -481,7 +481,7 @@ EncodedDataStatus SVGImage::dataChanged(bool allDataReceived)
m_page->settings().setShouldAllowUserInstalledFonts(false);

#if ENABLE(LAYER_BASED_SVG_ENGINE)
if (auto* observer = imageObserver())
if (auto observer = imageObserver())
m_page->settings().setLayerBasedSVGEngineEnabled(observer->layerBasedSVGEngineEnabled());
#endif
auto* localMainFrame = dynamicDowncast<LocalFrame>(m_page->mainFrame());
Expand Down
24 changes: 15 additions & 9 deletions Source/WebCore/svg/graphics/SVGImageClients.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include "EmptyClients.h"
#include "SVGImage.h"
#include <wtf/WeakPtr.h>

namespace WebCore {

Expand All @@ -47,35 +48,40 @@ class SVGImageChromeClient final : public EmptyChromeClient {
}

bool isSVGImageChromeClient() const final { return true; }
SVGImage* image() const { return m_image; }
SVGImage* image() const { return m_image.get(); }

private:
void chromeDestroyed() final
{
m_image = nullptr;
}

void invalidateContentsAndRootView(const IntRect& r) final
void invalidateContentsAndRootView(const IntRect& rect) final
{
// If m_image->m_page is null, we're being destroyed.
if (!m_image || !m_image->m_page)
RefPtr image { m_image.get() };

// If m_image->internalPage() is null, we're being destroyed.
if (!image || !image->internalPage())
return;

auto* imageObserver = m_image->imageObserver();
auto imageObserver = image->imageObserver();
if (!imageObserver)
return;

imageObserver->imageFrameAvailable(*m_image, m_image->isAnimating() ? ImageAnimatingState::Yes : ImageAnimatingState::No, &r);
imageObserver->imageFrameAvailable(*image, image->isAnimating() ? ImageAnimatingState::Yes : ImageAnimatingState::No, &rect);
}

bool scheduleRenderingUpdate() final
{
if (m_image && m_image->imageObserver())
m_image->imageObserver()->scheduleRenderingUpdate(*m_image);
RefPtr image { m_image.get() };
if (!image)
return true;
if (auto imageObserver = image->imageObserver())
imageObserver->scheduleRenderingUpdate(*image);
return true;
}

SVGImage* m_image;
WeakPtr<SVGImage> m_image;
};

} // namespace WebCore
10 changes: 9 additions & 1 deletion Tools/TestWebKitAPI/Tests/WebCore/SVGImageCasts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ using namespace WebCore;

class TestImageObserver : public ImageObserver {
public:
static Ref<TestImageObserver> create()
{
return adoptRef(*new TestImageObserver);
}

private:
TestImageObserver() = default;

URL sourceUrl() const final
{
return URL();
Expand Down Expand Up @@ -79,7 +87,7 @@ class TestImageObserver : public ImageObserver {

TEST(SVGImageCasts, SVGImageForContainerIsNotSVGImage)
{
TestImageObserver imageObserver;
auto imageObserver = TestImageObserver::create();
auto svgImage = SVGImage::create(imageObserver);
Image& svgImageBase = svgImage.get();
EXPECT_TRUE(is<SVGImage>(svgImageBase));
Expand Down

0 comments on commit 5507f06

Please sign in to comment.