summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics/cg/ImageSourceCG.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics/cg/ImageSourceCG.cpp')
-rw-r--r--WebCore/platform/graphics/cg/ImageSourceCG.cpp225
1 files changed, 225 insertions, 0 deletions
diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
new file mode 100644
index 0000000..73907c9
--- /dev/null
+++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ImageSource.h"
+
+#if PLATFORM(CG)
+
+#include "IntSize.h"
+#include "SharedBuffer.h"
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+static const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32");
+
+ImageSource::ImageSource()
+ : m_decoder(0)
+{
+}
+
+ImageSource::~ImageSource()
+{
+ clear();
+}
+
+void ImageSource::clear()
+{
+ if (m_decoder) {
+ CFRelease(m_decoder);
+ m_decoder = 0;
+ }
+}
+
+CFDictionaryRef imageSourceOptions()
+{
+ static CFDictionaryRef options;
+
+ if (!options) {
+ const void* keys[2] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32 };
+ const void* values[2] = { kCFBooleanTrue, kCFBooleanTrue };
+ options = CFDictionaryCreate(NULL, keys, values, 2,
+ &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ }
+ return options;
+}
+
+bool ImageSource::initialized() const
+{
+ return m_decoder;
+}
+
+void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
+{
+ if (!m_decoder)
+ m_decoder = CGImageSourceCreateIncremental(NULL);
+#if PLATFORM(MAC)
+ // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. We use SharedBuffer's ability
+ // to wrap itself inside CFData to get around this, ensuring that ImageIO is really looking at the SharedBuffer.
+ CFDataRef cfData = data->createCFData();
+#else
+ // If no NSData is available, then we know SharedBuffer will always just be a vector. That means no secret changes can occur to it behind the
+ // scenes. We use CFDataCreateWithBytesNoCopy in that case.
+ CFDataRef cfData = CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data->data()), data->size(), kCFAllocatorNull);
+#endif
+ CGImageSourceUpdateData(m_decoder, cfData, allDataReceived);
+ CFRelease(cfData);
+}
+
+bool ImageSource::isSizeAvailable()
+{
+ bool result = false;
+ CGImageSourceStatus imageSourceStatus = CGImageSourceGetStatus(m_decoder);
+
+ // Ragnaros yells: TOO SOON! You have awakened me TOO SOON, Executus!
+ if (imageSourceStatus >= kCGImageStatusIncomplete) {
+ CFDictionaryRef image0Properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions());
+ if (image0Properties) {
+ CFNumberRef widthNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties, kCGImagePropertyPixelWidth);
+ CFNumberRef heightNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties, kCGImagePropertyPixelHeight);
+ result = widthNumber && heightNumber;
+ CFRelease(image0Properties);
+ }
+ }
+
+ return result;
+}
+
+IntSize ImageSource::frameSizeAtIndex(size_t index) const
+{
+ IntSize result;
+ CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions());
+ if (properties) {
+ int w = 0, h = 0;
+ CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth);
+ if (num)
+ CFNumberGetValue(num, kCFNumberIntType, &w);
+ num = (CFNumberRef)CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight);
+ if (num)
+ CFNumberGetValue(num, kCFNumberIntType, &h);
+ result = IntSize(w, h);
+ CFRelease(properties);
+ }
+ return result;
+}
+
+IntSize ImageSource::size() const
+{
+ return frameSizeAtIndex(0);
+}
+
+int ImageSource::repetitionCount()
+{
+ int result = cAnimationLoopOnce; // No property means loop once.
+ if (!initialized())
+ return result;
+
+ // A property with value 0 means loop forever.
+ CFDictionaryRef properties = CGImageSourceCopyProperties(m_decoder, imageSourceOptions());
+ if (properties) {
+ CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary);
+ if (gifProperties) {
+ CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFLoopCount);
+ if (num)
+ CFNumberGetValue(num, kCFNumberIntType, &result);
+ } else
+ result = cAnimationNone; // Turns out we're not a GIF after all, so we don't animate.
+
+ CFRelease(properties);
+ }
+
+ return result;
+}
+
+size_t ImageSource::frameCount() const
+{
+ return m_decoder ? CGImageSourceGetCount(m_decoder) : 0;
+}
+
+CGImageRef ImageSource::createFrameAtIndex(size_t index)
+{
+ if (!initialized())
+ return 0;
+
+ CGImageRef image = CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions());
+ CFStringRef imageUTI = CGImageSourceGetType(m_decoder);
+ static const CFStringRef xbmUTI = CFSTR("public.xbitmap-image");
+ if (!imageUTI || !CFEqual(imageUTI, xbmUTI))
+ return image;
+
+ // If it is an xbm image, mask out all the white areas to render them transparent.
+ const CGFloat maskingColors[6] = {255, 255, 255, 255, 255, 255};
+ CGImageRef maskedImage = CGImageCreateWithMaskingColors(image, maskingColors);
+ if (!maskedImage)
+ return image;
+
+ CGImageRelease(image);
+ return maskedImage;
+}
+
+bool ImageSource::frameIsCompleteAtIndex(size_t index)
+{
+ return CGImageSourceGetStatusAtIndex(m_decoder, index) == kCGImageStatusComplete;
+}
+
+float ImageSource::frameDurationAtIndex(size_t index)
+{
+ if (!initialized())
+ return 0;
+
+ float duration = 0;
+ CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions());
+ if (properties) {
+ CFDictionaryRef typeProperties = (CFDictionaryRef)CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary);
+ if (typeProperties) {
+ CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(typeProperties, kCGImagePropertyGIFDelayTime);
+ if (num)
+ CFNumberGetValue(num, kCFNumberFloatType, &duration);
+ }
+ CFRelease(properties);
+ }
+
+ // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
+ // We follow WinIE's behavior and use a duration of 100 ms for any frames that specify
+ // a duration of <= 50 ms. See <http://bugs.webkit.org/show_bug.cgi?id=14413> or Radar 4051389 for more.
+ if (duration < 0.051f)
+ return 0.100f;
+ return duration;
+}
+
+bool ImageSource::frameHasAlphaAtIndex(size_t index)
+{
+ // Might be interesting to do this optimization on Mac some day, but for now we're just using this
+ // for the Cairo source, since it uses our decoders, and our decoders can answer this question.
+ // FIXME: Could return false for JPEG and other non-transparent image formats.
+ // FIXME: Could maybe return false for a GIF Frame if we have enough info in the GIF properties dictionary
+ // to determine whether or not a transparent color was defined.
+ return true;
+}
+
+}
+
+#endif // PLATFORM(CG)