[CG] PostScript images should be supported if they are sub-resource images
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 28 Nov 2017 23:09:42 +0000 (23:09 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 28 Nov 2017 23:09:42 +0000 (23:09 +0000)
https://bugs.webkit.org/show_bug.cgi?id=178502
Source/WebCore:

<rdar://problem/35102988>

Patch by Said Abou-Hallawa <sabouhallawa@apple.com> on 2017-11-28
Reviewed by Simon Fraser.

Make CachedImage detect the PostScript mime type and the file extension.
Let PDFDocumentImage replaces the PostScript data with the equivalent PDF
data and use it when creating the PDFDocument.

Test: fast/images/eps-as-image.html

* WebCore.xcodeproj/project.pbxproj:
* loader/cache/CachedImage.cpp:
(WebCore::CachedImage::isPDFRequest const):
(WebCore::CachedImage::isPostScriptRequest const):
These functions return whether the request is for a PDF or a PostScript
image. They check for the same conditions we do in WebPage::createPlugin().

(WebCore::CachedImage::createImage): Create a PDFDocumentImage for either
a PDF or a PostScript image. For PostScript, the data will be converted
to PDF when all the data is received.

(WebCore::CachedImage::updateBufferInternal): Use the size() of m_data
instead of using the m_image->data() to setEncodedSize(). Image::m_data
and CachedImage::m_data point to the same SharedBuffer.

(WebCore::CachedImage::convertedDataIfNeeded const): Convert the PostScript
data to PDF if the system can convert it. If the same can't convert it,
return null so loading the image will be canceled.

(WebCore::CachedImage::updateImageData): Get rid of the data argument since
we always send the member m_data to this function.

(WebCore::CachedImage::finishLoading): Convert the PostScript data to PDF
data since all the data is received. Use m_data to set setEncodedSize().

* loader/cache/CachedImage.h:
* platform/MIMETypeRegistry.cpp:
(WebCore::MIMETypeRegistry::isPostScriptMIMEType):
(WebCore::MIMETypeRegistry::isPDFOrPostScriptMIMEType):
* platform/MIMETypeRegistry.h:
* platform/graphics/cg/PDFDocumentImage.cpp:
(WebCore::PDFDocumentImage::PDFDocumentImage):
(WebCore::PDFDocumentImage::convertPostScriptDataToPDF):
* platform/graphics/cg/PDFDocumentImage.h:

Source/WebKit:

<rdar://problem/35102988>

Patch by Said Abou-Hallawa <sabouhallawa@apple.com> on 2017-11-28
Reviewed by Simon Fraser.

Make convertPostScriptDataToPDF() be as static function of PDFDocumentImage
in WebCore.

* WebProcess/Plugins/PDF/PDFPlugin.mm:
(WebKit::PDFPlugin::convertPostScriptDataIfNeeded):
(WebKit::convertPostScriptDataToPDF): Deleted.

LayoutTests:

Patch by Said Abou-Hallawa <sabouhallawa@apple.com> on 2017-11-28
Reviewed by Simon Fraser.

* TestExpectations:
* fast/images/eps-as-image-expected.html: Added.
* fast/images/eps-as-image.html: Added.
* fast/images/resources/green-100x100.eps: Added.
* platform/mac/TestExpectations:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@225241 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/fast/images/eps-as-image-expected.html [new file with mode: 0644]
LayoutTests/fast/images/eps-as-image.html [new file with mode: 0644]
LayoutTests/fast/images/resources/green-100x100.eps [new file with mode: 0644]
LayoutTests/platform/mac/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/loader/cache/CachedImage.cpp
Source/WebCore/loader/cache/CachedImage.h
Source/WebCore/platform/MIMETypeRegistry.cpp
Source/WebCore/platform/MIMETypeRegistry.h
Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp
Source/WebCore/platform/graphics/cg/PDFDocumentImage.h
Source/WebKit/ChangeLog
Source/WebKit/WebProcess/Plugins/PDF/PDFPlugin.mm

index d259e57..6da07e5 100644 (file)
@@ -1,3 +1,16 @@
+2017-11-28  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        [CG] PostScript images should be supported if they are sub-resource images
+        https://bugs.webkit.org/show_bug.cgi?id=178502
+
+        Reviewed by Simon Fraser.
+
+        * TestExpectations:
+        * fast/images/eps-as-image-expected.html: Added.
+        * fast/images/eps-as-image.html: Added.
+        * fast/images/resources/green-100x100.eps: Added.
+        * platform/mac/TestExpectations:
+
 2017-11-28  Daniel Bates  <dabates@apple.com>
 
         [Cocoa] First pass at implementing alternative presentation button element
index aea8b06..8bfff30 100644 (file)
@@ -53,8 +53,9 @@ fast/scrolling/latching [ Skip ]
 fast/forms/search/search-padding-cancel-results-buttons.html [ Skip ]
 fast/forms/search/search-results-hidden-crash.html [ Skip ]
 
-# This doesn't have to be platform-specific, but it's only implemented on Mac now.
+# These tests don't have to be platform-specific, but they are only implemented on Mac now.
 fast/url/user-visible [ Skip ]
+fast/images/eps-as-image.html [ Skip ]
 
 # Only Mac supports Dashboard widgets.
 fast/xmlhttprequest/set-dangerous-headers-in-dashboard.html [ WontFix ]
diff --git a/LayoutTests/fast/images/eps-as-image-expected.html b/LayoutTests/fast/images/eps-as-image-expected.html
new file mode 100644 (file)
index 0000000..b98a2d1
--- /dev/null
@@ -0,0 +1,11 @@
+<style>
+    div {
+        display: inline-block;
+        width: 100px;
+        height: 100px;
+        background-color: green;
+    }
+</style>
+<body>
+    <div></div>
+</body>
diff --git a/LayoutTests/fast/images/eps-as-image.html b/LayoutTests/fast/images/eps-as-image.html
new file mode 100644 (file)
index 0000000..8613a5d
--- /dev/null
@@ -0,0 +1,3 @@
+<body>
+    <img src="resources/green-100x100.eps">
+</body>
diff --git a/LayoutTests/fast/images/resources/green-100x100.eps b/LayoutTests/fast/images/resources/green-100x100.eps
new file mode 100644 (file)
index 0000000..c2e75e5
--- /dev/null
@@ -0,0 +1,10 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 0 0 100 100
+%%EndComments
+-1 -1 moveto
+100 -1 lineto
+100 100 lineto
+0 100 lineto
+closepath
+0 0.5 0 setrgbcolor
+fill
index 89890e2..5d9bb5e 100644 (file)
@@ -17,6 +17,7 @@ fast/forms/search/search-padding-cancel-results-buttons.html [ Pass ]
 fast/forms/search/search-results-hidden-crash.html [ Pass ]
 
 fast/url/user-visible [ Pass ]
+fast/images/eps-as-image.html [ Pass ]
 
 fast/text-autosizing/ios/ipad/programmatic-text-size-adjust.html [ Skip ]
 fast/text-autosizing/ios/ipad/text-size-adjust-inline-style.html [ Skip ]
index c482ff4..56566f0 100644 (file)
@@ -1,3 +1,52 @@
+2017-11-28  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        [CG] PostScript images should be supported if they are sub-resource images
+        https://bugs.webkit.org/show_bug.cgi?id=178502
+        <rdar://problem/35102988>
+
+        Reviewed by Simon Fraser.
+
+        Make CachedImage detect the PostScript mime type and the file extension.
+        Let PDFDocumentImage replaces the PostScript data with the equivalent PDF
+        data and use it when creating the PDFDocument.
+
+        Test: fast/images/eps-as-image.html
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * loader/cache/CachedImage.cpp:
+        (WebCore::CachedImage::isPDFRequest const):
+        (WebCore::CachedImage::isPostScriptRequest const):
+        These functions return whether the request is for a PDF or a PostScript 
+        image. They check for the same conditions we do in WebPage::createPlugin().
+
+        (WebCore::CachedImage::createImage): Create a PDFDocumentImage for either
+        a PDF or a PostScript image. For PostScript, the data will be converted
+        to PDF when all the data is received.
+
+        (WebCore::CachedImage::updateBufferInternal): Use the size() of m_data
+        instead of using the m_image->data() to setEncodedSize(). Image::m_data
+        and CachedImage::m_data point to the same SharedBuffer.
+
+        (WebCore::CachedImage::convertedDataIfNeeded const): Convert the PostScript
+        data to PDF if the system can convert it. If the same can't convert it,
+        return null so loading the image will be canceled.
+
+        (WebCore::CachedImage::updateImageData): Get rid of the data argument since
+        we always send the member m_data to this function.
+
+        (WebCore::CachedImage::finishLoading): Convert the PostScript data to PDF 
+        data since all the data is received. Use m_data to set setEncodedSize().
+
+        * loader/cache/CachedImage.h:
+        * platform/MIMETypeRegistry.cpp:
+        (WebCore::MIMETypeRegistry::isPostScriptMIMEType):
+        (WebCore::MIMETypeRegistry::isPDFOrPostScriptMIMEType):
+        * platform/MIMETypeRegistry.h:
+        * platform/graphics/cg/PDFDocumentImage.cpp:
+        (WebCore::PDFDocumentImage::PDFDocumentImage):
+        (WebCore::PDFDocumentImage::convertPostScriptDataToPDF):
+        * platform/graphics/cg/PDFDocumentImage.h:
+
 2017-11-14  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         Move JSONValues to WTF and convert uses of InspectorValues.h to JSONValues.h
index 4c66aa8..942c670 100644 (file)
                B25599850D00D8BA00BB825C /* SVGFEImage.h in Headers */ = {isa = PBXBuildFile; fileRef = B25598EB0D00D8B900BB825C /* SVGFEImage.h */; };
                B25599A40D00D8BA00BB825C /* SVGImage.h in Headers */ = {isa = PBXBuildFile; fileRef = B255990C0D00D8B900BB825C /* SVGImage.h */; };
                B25599A50D00D8BA00BB825C /* EmptyClients.h in Headers */ = {isa = PBXBuildFile; fileRef = B255990D0D00D8B900BB825C /* EmptyClients.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               B27535650B053814002CE64F /* PDFDocumentImage.h in Headers */ = {isa = PBXBuildFile; fileRef = B27535370B053814002CE64F /* PDFDocumentImage.h */; };
+               B27535650B053814002CE64F /* PDFDocumentImage.h in Headers */ = {isa = PBXBuildFile; fileRef = B27535370B053814002CE64F /* PDFDocumentImage.h */; settings = {ATTRIBUTES = (Private, ); }; };
                B27535670B053814002CE64F /* Color.h in Headers */ = {isa = PBXBuildFile; fileRef = B27535390B053814002CE64F /* Color.h */; settings = {ATTRIBUTES = (Private, ); }; };
                B27535690B053814002CE64F /* FloatPoint.h in Headers */ = {isa = PBXBuildFile; fileRef = B275353B0B053814002CE64F /* FloatPoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
                B275356B0B053814002CE64F /* FloatRect.h in Headers */ = {isa = PBXBuildFile; fileRef = B275353D0B053814002CE64F /* FloatRect.h */; settings = {ATTRIBUTES = (Private, ); }; };
index 3ef3ae3..4101d3b 100644 (file)
@@ -34,6 +34,7 @@
 #include "FrameLoaderClient.h"
 #include "FrameLoaderTypes.h"
 #include "FrameView.h"
+#include "MIMETypeRegistry.h"
 #include "MemoryCache.h"
 #include "RenderElement.h"
 #include "SVGImage.h"
@@ -308,6 +309,20 @@ void CachedImage::checkShouldPaintBrokenImage()
     m_shouldPaintBrokenImage = m_loader->frameLoader()->client().shouldPaintBrokenImage(url());
 }
 
+bool CachedImage::isPDFResource() const
+{
+    if (m_response.mimeType().isEmpty())
+        return url().path().endsWithIgnoringASCIICase(".pdf");
+    return MIMETypeRegistry::isPDFMIMEType(m_response.mimeType());
+}
+
+bool CachedImage::isPostScriptResource() const
+{
+    if (m_response.mimeType().isEmpty())
+        return url().path().endsWithIgnoringASCIICase(".ps");
+    return MIMETypeRegistry::isPostScriptMIMEType(m_response.mimeType());
+}
+
 void CachedImage::clear()
 {
     destroyDecodedData();
@@ -329,8 +344,8 @@ inline void CachedImage::createImage()
         auto svgImage = SVGImage::create(*m_imageObserver);
         m_svgImageCache = std::make_unique<SVGImageCache>(svgImage.ptr());
         m_image = WTFMove(svgImage);
+    } else if (isPDFResource() || isPostScriptResource()) {
 #if USE(CG) && !USE(WEBKIT_IMAGE_DECODERS)
-    } else if (m_response.mimeType() == "application/pdf") {
         m_image = PDFDocumentImage::create(m_imageObserver.get());
 #endif
     } else
@@ -411,18 +426,32 @@ inline void CachedImage::clearImage()
 void CachedImage::updateBufferInternal(SharedBuffer& data)
 {
     m_data = &data;
+    setEncodedSize(m_data->size());
     createImage();
-    setEncodedSize(m_image->data() ? m_image->data()->size() : 0);
 
     // Don't update the image with the new buffer very often. Changing the decoder
     // internal data and repainting the observers sometimes are very expensive operations.
     if (shouldDeferUpdateImageData())
         return;
-    
-    // Have the image update its data from its internal buffer. Decoding the image data
-    // will be delayed until info (like size or specific image frames) are queried which
-    // usually happens when the observers are repainted.
-    EncodedDataStatus encodedDataStatus = updateImageData(&data, false);
+
+    EncodedDataStatus encodedDataStatus = EncodedDataStatus::Unknown;
+
+    if (isPostScriptResource()) {
+#if PLATFORM(MAC) && !USE(WEBKIT_IMAGE_DECODERS)
+        // Delay updating the image with the PostScript data till all the data
+        // is received so it can be converted to PDF data.
+        return;
+#else
+        // Set the encodedDataStatus to Error so loading this image will be canceled.
+        encodedDataStatus = EncodedDataStatus::Error;
+#endif
+    } else {
+        // Have the image update its data from its internal buffer. Decoding the image data
+        // will be delayed until info (like size or specific image frames) are queried which
+        // usually happens when the observers are repainted.
+        encodedDataStatus = updateImageData(false);
+    }
+
     if (encodedDataStatus > EncodedDataStatus::Error && encodedDataStatus < EncodedDataStatus::SizeAvailable)
         return;
 
@@ -449,6 +478,19 @@ bool CachedImage::shouldDeferUpdateImageData() const
     return (MonotonicTime::now() - m_lastUpdateImageDataTime).seconds() < updateImageDataBackoffIntervals[interval];
 }
 
+RefPtr<SharedBuffer> CachedImage::convertedDataIfNeeded(SharedBuffer* data) const
+{
+    if (!data || !isPostScriptResource())
+        return data;
+#if PLATFORM(MAC) && !USE(WEBKIT_IMAGE_DECODERS)
+    return SharedBuffer::create(PDFDocumentImage::convertPostScriptDataToPDF(data->createCFData()).get());
+#else
+    // Loading the image should have been canceled if the system does not support converting PostScript to PDF.
+    ASSERT_NOT_REACHED();
+    return nullptr;
+#endif
+}
+
 void CachedImage::didUpdateImageData()
 {
     m_lastUpdateImageDataTime = MonotonicTime::now();
@@ -456,11 +498,11 @@ void CachedImage::didUpdateImageData()
     ++m_updateImageDataCount;
 }
 
-EncodedDataStatus CachedImage::updateImageData(SharedBuffer* data, bool allDataReceived)
+EncodedDataStatus CachedImage::updateImageData(bool allDataReceived)
 {
-    if (!m_image)
+    if (!m_image || !m_data)
         return EncodedDataStatus::Error;
-    EncodedDataStatus result = m_image->setData(data, allDataReceived);
+    EncodedDataStatus result = m_image->setData(m_data.get(), allDataReceived);
     didUpdateImageData();
     return result;
 }
@@ -481,11 +523,13 @@ void CachedImage::updateData(const char* data, unsigned length)
 
 void CachedImage::finishLoading(SharedBuffer* data)
 {
-    m_data = data;
-    if (!m_image && data)
+    m_data = convertedDataIfNeeded(data);
+    if (m_data) {
+        setEncodedSize(m_data->size());
         createImage();
+    }
 
-    EncodedDataStatus encodedDataStatus = updateImageData(data, true);
+    EncodedDataStatus encodedDataStatus = updateImageData(true);
 
     if (encodedDataStatus == EncodedDataStatus::Error || m_image->isNull()) {
         // Image decoding failed; the image data is malformed.
@@ -496,8 +540,6 @@ void CachedImage::finishLoading(SharedBuffer* data)
     }
 
     notifyObservers();
-    if (m_image)
-        setEncodedSize(m_image->data() ? m_image->data()->size() : 0);
     CachedResource::finishLoading(data);
 }
 
index 811c28a..2643457 100644 (file)
@@ -94,6 +94,9 @@ private:
 
     void setBodyDataFrom(const CachedResource&) final;
 
+    bool isPDFResource() const;
+    bool isPostScriptResource() const;
+
     void createImage();
     void clearImage();
     // If not null, changeRect is the changed part of the image.
@@ -110,8 +113,9 @@ private:
     void destroyDecodedData() override;
 
     bool shouldDeferUpdateImageData() const;
+    RefPtr<SharedBuffer> convertedDataIfNeeded(SharedBuffer* data) const;
     void didUpdateImageData();
-    EncodedDataStatus updateImageData(SharedBuffer*, bool allDataReceived);
+    EncodedDataStatus updateImageData(bool allDataReceived);
     void updateData(const char* data, unsigned length) override;
     void error(CachedResource::Status) override;
     void responseReceived(const ResourceResponse&) override;
index a799e87..e578667 100644 (file)
@@ -603,11 +603,6 @@ bool MIMETypeRegistry::isJavaAppletMIMEType(const String& mimeType)
         || startsWithLettersIgnoringASCIICase(mimeType, "application/x-java-vm");
 }
 
-bool MIMETypeRegistry::isPDFOrPostScriptMIMEType(const String& mimeType)
-{
-    return isPDFMIMEType(mimeType) || mimeType == "application/postscript";
-}
-
 bool MIMETypeRegistry::isPDFMIMEType(const String& mimeType)
 {
     if (mimeType.isEmpty())
@@ -617,6 +612,16 @@ bool MIMETypeRegistry::isPDFMIMEType(const String& mimeType)
     return pdfMIMETypes->contains(mimeType);
 }
 
+bool MIMETypeRegistry::isPostScriptMIMEType(const String& mimeType)
+{
+    return mimeType == "application/postscript";
+}
+
+bool MIMETypeRegistry::isPDFOrPostScriptMIMEType(const String& mimeType)
+{
+    return isPDFMIMEType(mimeType) || isPostScriptMIMEType(mimeType);
+}
+
 bool MIMETypeRegistry::canShowMIMEType(const String& mimeType)
 {
     if (isSupportedImageMIMEType(mimeType) || isSupportedNonImageMIMEType(mimeType) || isSupportedMediaMIMEType(mimeType))
index 541d740..8e14317 100644 (file)
@@ -84,8 +84,9 @@ public:
     static bool isApplicationPluginMIMEType(const String& mimeType);
 
     // Check to see if a MIME type is one of the common PDF/PS types.
-    WEBCORE_EXPORT static bool isPDFOrPostScriptMIMEType(const String& mimeType);
     static bool isPDFMIMEType(const String& mimeType);
+    static bool isPostScriptMIMEType(const String& mimeType);
+    WEBCORE_EXPORT static bool isPDFOrPostScriptMIMEType(const String& mimeType);
 
     // Check to see if a MIME type is suitable for being shown inside a page.
     // Returns true if any of isSupportedImageMIMEType(), isSupportedNonImageMIMEType(),
index b8de7e9..ab5c613 100644 (file)
@@ -56,9 +56,6 @@ namespace WebCore {
 
 PDFDocumentImage::PDFDocumentImage(ImageObserver* observer)
     : Image(observer)
-    , m_cachedBytes(0)
-    , m_rotationDegrees(0)
-    , m_hasPage(false)
 {
 }
 
@@ -356,6 +353,25 @@ void PDFDocumentImage::drawPDFPage(GraphicsContext& context)
 
 #endif // !USE(PDFKIT_FOR_PDFDOCUMENTIMAGE)
 
+#if PLATFORM(MAC)
+
+RetainPtr<CFMutableDataRef> PDFDocumentImage::convertPostScriptDataToPDF(RetainPtr<CFDataRef>&& postScriptData)
+{
+    // Convert PostScript to PDF using the Quartz 2D API.
+    // http://developer.apple.com/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_ps_convert/chapter_16_section_1.html
+
+    CGPSConverterCallbacks callbacks = { };
+    auto converter = adoptCF(CGPSConverterCreate(0, &callbacks, 0));
+    auto provider = adoptCF(CGDataProviderCreateWithCFData(postScriptData.get()));
+    auto pdfData = adoptCF(CFDataCreateMutable(kCFAllocatorDefault, 0));
+    auto consumer = adoptCF(CGDataConsumerCreateWithCFData(pdfData.get()));
+
+    CGPSConverterConvert(converter.get(), provider.get(), consumer.get(), 0);
+    return pdfData;
+}
+
+#endif
+
 void PDFDocumentImage::dump(TextStream& ts) const
 {
     Image::dump(ts);
index 3f03668..155bcd7 100644 (file)
@@ -54,6 +54,10 @@ public:
     }
 
     void setPdfImageCachingPolicy(PDFImageCachingPolicy);
+    
+#if PLATFORM(MAC)
+    WEBCORE_EXPORT static RetainPtr<CFMutableDataRef> convertPostScriptDataToPDF(RetainPtr<CFDataRef>&& postScriptData);
+#endif
 
 private:
     PDFDocumentImage(ImageObserver*);
@@ -101,11 +105,11 @@ private:
     AffineTransform m_cachedTransform;
     FloatSize m_cachedDestinationSize;
     FloatRect m_cachedSourceRect;
-    size_t m_cachedBytes;
+    size_t m_cachedBytes { 0 };
 
     FloatRect m_cropBox;
-    int m_rotationDegrees; // Can only be 0, 90, 180, or 270 degrees.
-    bool m_hasPage;
+    int m_rotationDegrees { 0 }; // Can only be 0, 90, 180, or 270 degrees.
+    bool m_hasPage { false };
 };
 
 }
index ef41b59..df30f24 100644 (file)
@@ -1,3 +1,18 @@
+2017-11-28  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        [CG] PostScript images should be supported if they are sub-resource images
+        https://bugs.webkit.org/show_bug.cgi?id=178502
+        <rdar://problem/35102988>
+
+        Reviewed by Simon Fraser.
+
+        Make convertPostScriptDataToPDF() be as static function of PDFDocumentImage
+        in WebCore.
+
+        * WebProcess/Plugins/PDF/PDFPlugin.mm:
+        (WebKit::PDFPlugin::convertPostScriptDataIfNeeded):
+        (WebKit::convertPostScriptDataToPDF): Deleted.
+
 2017-11-28  Alex Christensen  <achristensen@webkit.org>
 
         Add SPI for adding strings directly to a _WKVisitedLinkStore
index e3f88b1..86c80d4 100644 (file)
@@ -70,6 +70,7 @@
 #import <WebCore/LocalizedStrings.h>
 #import <WebCore/MainFrame.h>
 #import <WebCore/MouseEvent.h>
+#import <WebCore/PDFDocumentImage.h>
 #import <WebCore/Page.h>
 #import <WebCore/Pasteboard.h>
 #import <WebCore/PluginData.h>
@@ -979,29 +980,13 @@ JSObjectRef PDFPlugin::makeJSPDFDoc(JSContextRef ctx)
     return JSObjectMake(ctx, jsPDFDocClass, this);
 }
 
-static RetainPtr<CFMutableDataRef> convertPostScriptDataToPDF(RetainPtr<CFDataRef> postScriptData)
-{
-    // Convert PostScript to PDF using the Quartz 2D API.
-    // http://developer.apple.com/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_ps_convert/chapter_16_section_1.html
-
-    CGPSConverterCallbacks callbacks = { 0, 0, 0, 0, 0, 0, 0, 0 };
-    RetainPtr<CGPSConverterRef> converter = adoptCF(CGPSConverterCreate(0, &callbacks, 0));
-    RetainPtr<CGDataProviderRef> provider = adoptCF(CGDataProviderCreateWithCFData(postScriptData.get()));
-    RetainPtr<CFMutableDataRef> pdfData = adoptCF(CFDataCreateMutable(kCFAllocatorDefault, 0));
-    RetainPtr<CGDataConsumerRef> consumer = adoptCF(CGDataConsumerCreateWithCFData(pdfData.get()));
-    
-    CGPSConverterConvert(converter.get(), provider.get(), consumer.get(), 0);
-    
-    return pdfData;
-}
-
 void PDFPlugin::convertPostScriptDataIfNeeded()
 {
     if (!m_isPostScript)
         return;
 
     m_suggestedFilename = String(m_suggestedFilename + ".pdf");
-    m_data = convertPostScriptDataToPDF(m_data);
+    m_data = PDFDocumentImage::convertPostScriptDataToPDF(WTFMove(m_data));
 }
 
 void PDFPlugin::pdfDocumentDidLoad()