summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics/cg
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:15 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:15 -0800
commit1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353 (patch)
tree4457a7306ea5acb43fe05bfe0973b1f7faf97ba2 /WebCore/platform/graphics/cg
parent9364f22aed35e1a1e9d07c121510f80be3ab0502 (diff)
downloadexternal_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.zip
external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.gz
external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.bz2
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'WebCore/platform/graphics/cg')
-rw-r--r--WebCore/platform/graphics/cg/AffineTransformCG.cpp8
-rw-r--r--WebCore/platform/graphics/cg/GradientCG.cpp82
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContextCG.cpp309
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h8
-rw-r--r--WebCore/platform/graphics/cg/ImageBufferCG.cpp244
-rw-r--r--WebCore/platform/graphics/cg/ImageBufferData.h42
-rw-r--r--WebCore/platform/graphics/cg/ImageCG.cpp147
-rw-r--r--WebCore/platform/graphics/cg/ImageSourceCG.cpp48
-rw-r--r--WebCore/platform/graphics/cg/PDFDocumentImage.h15
-rw-r--r--WebCore/platform/graphics/cg/PathCG.cpp12
-rw-r--r--WebCore/platform/graphics/cg/PatternCG.cpp77
11 files changed, 824 insertions, 168 deletions
diff --git a/WebCore/platform/graphics/cg/AffineTransformCG.cpp b/WebCore/platform/graphics/cg/AffineTransformCG.cpp
index 8fdd1e6..4f0bca0 100644
--- a/WebCore/platform/graphics/cg/AffineTransformCG.cpp
+++ b/WebCore/platform/graphics/cg/AffineTransformCG.cpp
@@ -37,8 +37,8 @@
namespace WebCore {
AffineTransform::AffineTransform()
+ : m_transform(CGAffineTransformIdentity)
{
- m_transform = CGAffineTransformIdentity;
}
AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty)
@@ -51,9 +51,9 @@ AffineTransform::AffineTransform(double a, double b, double c, double d, double
narrowPrecisionToCGFloat(ty));
}
-AffineTransform::AffineTransform(CGAffineTransform t)
+AffineTransform::AffineTransform(const PlatformAffineTransform& t)
+ : m_transform(t)
{
- m_transform = t;
}
void AffineTransform::setMatrix(double a, double b, double c, double d, double tx, double ty)
@@ -190,7 +190,7 @@ AffineTransform AffineTransform::inverse() const
return AffineTransform();
}
-AffineTransform::operator CGAffineTransform() const
+AffineTransform::operator PlatformAffineTransform() const
{
return m_transform;
}
diff --git a/WebCore/platform/graphics/cg/GradientCG.cpp b/WebCore/platform/graphics/cg/GradientCG.cpp
new file mode 100644
index 0000000..c189fd5
--- /dev/null
+++ b/WebCore/platform/graphics/cg/GradientCG.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * 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 "Gradient.h"
+
+#include "CSSParser.h"
+#include "GraphicsContext.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+void Gradient::platformDestroy()
+{
+ CGShadingRelease(m_gradient);
+ m_gradient = 0;
+}
+
+static void gradientCallback(void* info, const CGFloat* in, CGFloat* out)
+{
+ float r, g, b, a;
+ static_cast<const Gradient*>(info)->getColor(*in, &r, &g, &b, &a);
+ out[0] = r;
+ out[1] = g;
+ out[2] = b;
+ out[3] = a;
+}
+
+CGShadingRef Gradient::platformGradient()
+{
+ if (m_gradient)
+ return m_gradient;
+
+ const CGFloat intervalRanges[2] = { 0, 1 };
+ const CGFloat colorComponentRanges[4 * 2] = { 0, 1, 0, 1, 0, 1, 0, 1 };
+ const CGFunctionCallbacks gradientCallbacks = { 0, gradientCallback, 0 };
+ CGFunctionRef colorFunction = CGFunctionCreate(this, 1, intervalRanges, 4, colorComponentRanges, &gradientCallbacks);
+
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+
+ if (m_radial)
+ m_gradient = CGShadingCreateRadial(colorSpace, m_p0, m_r0, m_p1, m_r1, colorFunction, true, true);
+ else
+ m_gradient = CGShadingCreateAxial(colorSpace, m_p0, m_p1, colorFunction, true, true);
+
+ CGColorSpaceRelease(colorSpace);
+ CGFunctionRelease(colorFunction);
+
+ return m_gradient;
+}
+
+void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
+{
+ context->clip(rect);
+ CGContextDrawShading(context->platformContext(), platformGradient());
+}
+
+} //namespace
diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
index c490dcb..3f0e6e7 100644
--- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
+++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,11 +30,21 @@
#include "AffineTransform.h"
#include "FloatConversion.h"
+#include "GraphicsContextPrivate.h"
#include "GraphicsContextPlatformPrivateCG.h"
+#include "ImageBuffer.h"
#include "KURL.h"
#include "Path.h"
+#include "Pattern.h"
+#include <CoreGraphics/CGBitmapContext.h>
#include <CoreGraphics/CGPDFContext.h>
#include <wtf/MathExtras.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/RetainPtr.h>
+
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+#define HAVE_CG_INTERPOLATION_MEDIUM 1
+#endif
using namespace std;
@@ -98,6 +109,8 @@ void GraphicsContext::restorePlatformState()
// Draws a filled rectangle with a stroked border.
void GraphicsContext::drawRect(const IntRect& rect)
{
+ // FIXME: this function does not handle patterns and gradients
+ // like drawPath does, it probably should.
if (paintingDisabled())
return;
@@ -252,14 +265,7 @@ void GraphicsContext::drawEllipse(const IntRect& rect)
CGContextAddArc(context, rect.x() + r, rect.y() + r, r, 0.0f, 2.0f * piFloat, 0);
CGContextClosePath(context);
- if (fillColor().alpha()) {
- if (strokeStyle() != NoStroke)
- // stroke and fill
- CGContextDrawPath(context, kCGPathFillStroke);
- else
- CGContextFillPath(context);
- } else if (strokeStyle() != NoStroke)
- CGContextStrokePath(context);
+ drawPath();
}
@@ -372,29 +378,177 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points
CGContextAddLineToPoint(context, points[i].x(), points[i].y());
CGContextClosePath(context);
- if (fillColor().alpha()) {
- if (strokeStyle() != NoStroke)
- CGContextDrawPath(context, kCGPathEOFillStroke);
- else
- CGContextEOFillPath(context);
- } else
- CGContextStrokePath(context);
+ drawPath();
CGContextRestoreGState(context);
}
-void GraphicsContext::fillRect(const IntRect& rect, const Color& color)
+static void applyStrokePattern(GraphicsContext* context, Pattern* pattern)
+{
+ CGContextRef cgContext = context->platformContext();
+
+ CGPatternRef platformPattern = pattern->createPlatformPattern(context->getCTM());
+ if (!platformPattern)
+ return;
+
+ CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(0);
+ CGContextSetStrokeColorSpace(cgContext, patternSpace);
+ CGColorSpaceRelease(patternSpace);
+
+ const CGFloat patternAlpha = 1;
+ CGContextSetStrokePattern(cgContext, platformPattern, &patternAlpha);
+ CGPatternRelease(platformPattern);
+}
+
+static void applyFillPattern(GraphicsContext* context, Pattern* pattern)
+{
+ CGContextRef cgContext = context->platformContext();
+
+ CGPatternRef platformPattern = pattern->createPlatformPattern(context->getCTM());
+ if (!platformPattern)
+ return;
+
+ CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(0);
+ CGContextSetFillColorSpace(cgContext, patternSpace);
+ CGColorSpaceRelease(patternSpace);
+
+ const CGFloat patternAlpha = 1;
+ CGContextSetFillPattern(cgContext, platformPattern, &patternAlpha);
+ CGPatternRelease(platformPattern);
+}
+
+static inline bool calculateDrawingMode(const GraphicsContextState& state, CGPathDrawingMode& mode)
+{
+ bool shouldFill = state.fillColorSpace == PatternColorSpace || state.fillColor.alpha();
+ bool shouldStroke = state.strokeColorSpace == PatternColorSpace || (state.strokeStyle != NoStroke && state.strokeColor.alpha());
+ bool useEOFill = state.fillRule == RULE_EVENODD;
+
+ if (shouldFill) {
+ if (shouldStroke) {
+ if (useEOFill)
+ mode = kCGPathEOFillStroke;
+ else
+ mode = kCGPathFillStroke;
+ } else { // fill, no stroke
+ if (useEOFill)
+ mode = kCGPathEOFill;
+ else
+ mode = kCGPathFill;
+ }
+ } else {
+ // Setting mode to kCGPathStroke even if shouldStroke is false. In that case, we return false and mode will not be used,
+ // but the compiler will not compain about an uninitialized variable.
+ mode = kCGPathStroke;
+ }
+
+ return shouldFill || shouldStroke;
+}
+
+void GraphicsContext::drawPath()
{
if (paintingDisabled())
return;
- if (color.alpha()) {
- CGContextRef context = platformContext();
- Color oldFillColor = fillColor();
- if (oldFillColor != color)
- setCGFillColor(context, color);
+
+ CGContextRef context = platformContext();
+ const GraphicsContextState& state = m_common->state;
+
+ if (state.fillColorSpace == GradientColorSpace || state.strokeColorSpace == GradientColorSpace) {
+ // We don't have any optimized way to fill & stroke a path using gradients
+ fillPath();
+ strokePath();
+ return;
+ }
+
+ if (state.fillColorSpace == PatternColorSpace)
+ applyFillPattern(this, m_common->state.fillPattern.get());
+ if (state.strokeColorSpace == PatternColorSpace)
+ applyStrokePattern(this, m_common->state.strokePattern.get());
+
+ CGPathDrawingMode drawingMode;
+ if (calculateDrawingMode(state, drawingMode))
+ CGContextDrawPath(context, drawingMode);
+}
+
+static inline void fillPathWithFillRule(CGContextRef context, WindRule fillRule)
+{
+ if (fillRule == RULE_EVENODD)
+ CGContextEOFillPath(context);
+ else
+ CGContextFillPath(context);
+}
+
+void GraphicsContext::fillPath()
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+ switch (m_common->state.fillColorSpace) {
+ case SolidColorSpace:
+ if (fillColor().alpha())
+ fillPathWithFillRule(context, fillRule());
+ break;
+ case PatternColorSpace:
+ applyFillPattern(this, m_common->state.fillPattern.get());
+ fillPathWithFillRule(context, fillRule());
+ break;
+ case GradientColorSpace:
+ CGContextSaveGState(context);
+ if (fillRule() == RULE_EVENODD)
+ CGContextEOClip(context);
+ else
+ CGContextClip(context);
+ CGContextDrawShading(context, m_common->state.fillGradient->platformGradient());
+ CGContextRestoreGState(context);
+ break;
+ }
+}
+
+void GraphicsContext::strokePath()
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+ switch (m_common->state.strokeColorSpace) {
+ case SolidColorSpace:
+ if (fillColor().alpha())
+ CGContextStrokePath(context);
+ break;
+ case PatternColorSpace:
+ applyStrokePattern(this, m_common->state.strokePattern.get());
+ CGContextStrokePath(context);
+ break;
+ case GradientColorSpace:
+ CGContextSaveGState(context);
+ CGContextReplacePathWithStrokedPath(context);
+ CGContextClip(context);
+ CGContextDrawShading(context, m_common->state.strokeGradient->platformGradient());
+ CGContextRestoreGState(context);
+ break;
+ }
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+ CGContextRef context = platformContext();
+ switch (m_common->state.fillColorSpace) {
+ case SolidColorSpace:
+ if (fillColor().alpha())
+ CGContextFillRect(context, rect);
+ break;
+ case PatternColorSpace:
+ applyFillPattern(this, m_common->state.fillPattern.get());
CGContextFillRect(context, rect);
- if (oldFillColor != color)
- setCGFillColor(context, oldFillColor);
+ break;
+ case GradientColorSpace:
+ CGContextSaveGState(context);
+ CGContextClipToRect(context, rect);
+ CGContextDrawShading(context, m_common->state.fillGradient->platformGradient());
+ CGContextRestoreGState(context);
+ break;
}
}
@@ -424,14 +578,13 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef
setCGFillColor(context, color);
addPath(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight));
- CGContextFillPath(context);
+ fillPath();
if (oldFillColor != color)
setCGFillColor(context, oldFillColor);
}
-
-void GraphicsContext::clip(const IntRect& rect)
+void GraphicsContext::clip(const FloatRect& rect)
{
if (paintingDisabled())
return;
@@ -478,6 +631,18 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness
CGContextEOClip(context);
}
+void GraphicsContext::clipToImageBuffer(const FloatRect& rect, const ImageBuffer* imageBuffer)
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextTranslateCTM(platformContext(), rect.x(), rect.y() + rect.height());
+ CGContextScaleCTM(platformContext(), 1, -1);
+ CGContextClipToMask(platformContext(), FloatRect(FloatPoint(), rect.size()), imageBuffer->image()->getCGImageRef());
+ CGContextScaleCTM(platformContext(), 1, -1);
+ CGContextTranslateCTM(platformContext(), -rect.x(), -rect.y() - rect.height());
+}
+
void GraphicsContext::beginTransparencyLayer(float opacity)
{
if (paintingDisabled())
@@ -501,19 +666,28 @@ void GraphicsContext::endTransparencyLayer()
m_data->m_userToDeviceTransformKnownToBeIdentity = false;
}
-void GraphicsContext::setShadow(const IntSize& size, int blur, const Color& color)
+void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Color& color)
{
- // Extreme "blur" values can make text drawing crash or take crazy long times, so clamp
- blur = min(blur, 1000);
-
if (paintingDisabled())
return;
CGContextRef context = platformContext();
+ CGAffineTransform transform = CGContextGetCTM(context);
+
+ CGFloat A = transform.a * transform.a + transform.b * transform.b;
+ CGFloat B = transform.a * transform.c + transform.b * transform.d;
+ CGFloat C = B;
+ CGFloat D = transform.c * transform.c + transform.d * transform.d;
- CGFloat width = size.width();
- CGFloat height = size.height();
+ CGFloat smallEigenvalue = narrowPrecisionToCGFloat(sqrt(0.5 * ((A + D) - sqrt(4 * B * C + (A - D) * (A - D)))));
+
+ // Extreme "blur" values can make text drawing crash or take crazy long times, so clamp
+ CGFloat blurRadius = min(blur * smallEigenvalue, narrowPrecisionToCGFloat(1000.0));
+
+ CGSize sizeInDeviceSpace = CGSizeApplyAffineTransform(size, transform);
+
+ CGFloat width = sizeInDeviceSpace.width;
+ CGFloat height = sizeInDeviceSpace.height;
-#ifdef BUILDING_ON_TIGER
// Work around <rdar://problem/5539388> by ensuring that the offsets will get truncated
// to the desired integer.
static const CGFloat extraShadowOffset = narrowPrecisionToCGFloat(1.0 / 128);
@@ -526,23 +700,22 @@ void GraphicsContext::setShadow(const IntSize& size, int blur, const Color& colo
height += extraShadowOffset;
else if (height < 0)
height -= extraShadowOffset;
-#endif
// Check for an invalid color, as this means that the color was not set for the shadow
// and we should therefore just use the default shadow color.
if (!color.isValid())
- CGContextSetShadow(context, CGSizeMake(width, -height), blur); // y is flipped.
+ CGContextSetShadow(context, CGSizeMake(width, height), blurRadius);
else {
CGColorRef colorCG = cgColor(color);
CGContextSetShadowWithColor(context,
- CGSizeMake(width, -height), // y is flipped.
- blur,
+ CGSizeMake(width, height),
+ blurRadius,
colorCG);
CGColorRelease(colorCG);
}
}
-void GraphicsContext::clearShadow()
+void GraphicsContext::clearPlatformShadow()
{
if (paintingDisabled())
return;
@@ -594,6 +767,11 @@ void GraphicsContext::setLineCap(LineCap cap)
}
}
+void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
+{
+ CGContextSetLineDash(platformContext(), dashOffset, dashes.data(), dashes.size());
+}
+
void GraphicsContext::setLineJoin(LineJoin join)
{
if (paintingDisabled())
@@ -610,7 +788,7 @@ void GraphicsContext::setLineJoin(LineJoin join)
break;
}
}
-
+
void GraphicsContext::beginPath()
{
CGContextBeginPath(platformContext());
@@ -789,20 +967,57 @@ void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
}
}
-void GraphicsContext::setUseLowQualityImageInterpolation(bool lowQualityMode)
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality mode)
{
if (paintingDisabled())
return;
-
- CGContextSetInterpolationQuality(platformContext(), lowQualityMode ? kCGInterpolationNone : kCGInterpolationDefault);
+
+ CGInterpolationQuality quality = kCGInterpolationDefault;
+ switch (mode) {
+ case InterpolationDefault:
+ quality = kCGInterpolationDefault;
+ break;
+ case InterpolationNone:
+ quality = kCGInterpolationNone;
+ break;
+ case InterpolationLow:
+ quality = kCGInterpolationLow;
+ break;
+
+ // Fall through to InterpolationHigh if kCGInterpolationMedium is not available
+ case InterpolationMedium:
+#if HAVE(CG_INTERPOLATION_MEDIUM)
+ quality = kCGInterpolationMedium;
+ break;
+#endif
+ case InterpolationHigh:
+ quality = kCGInterpolationHigh;
+ break;
+ }
+ CGContextSetInterpolationQuality(platformContext(), quality);
}
-bool GraphicsContext::useLowQualityImageInterpolation() const
+InterpolationQuality GraphicsContext::imageInterpolationQuality() const
{
if (paintingDisabled())
- return false;
-
- return CGContextGetInterpolationQuality(platformContext());
+ return InterpolationDefault;
+
+ CGInterpolationQuality quality = CGContextGetInterpolationQuality(platformContext());
+ switch (quality) {
+ case kCGInterpolationDefault:
+ return InterpolationDefault;
+ case kCGInterpolationNone:
+ return InterpolationNone;
+ case kCGInterpolationLow:
+ return InterpolationLow;
+#if HAVE(CG_INTERPOLATION_MEDIUM)
+ case kCGInterpolationMedium:
+ return InterpolationMedium;
+#endif
+ case kCGInterpolationHigh:
+ return InterpolationHigh;
+ }
+ return InterpolationDefault;
}
void GraphicsContext::setPlatformTextDrawingMode(int mode)
@@ -924,6 +1139,6 @@ void GraphicsContext::setCompositeOperation(CompositeOperator mode)
CGContextSetBlendMode(platformContext(), target);
}
#endif
-
+
}
diff --git a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
index 937481b..8827ff7 100644
--- a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
+++ b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
@@ -45,11 +45,11 @@ public:
CGContextRelease(m_cgContext);
}
-#if PLATFORM(MAC)
+#if PLATFORM(MAC) || PLATFORM(CHROMIUM)
// These methods do nothing on Mac.
void save() {}
void restore() {}
- void clip(const IntRect&) {}
+ void clip(const FloatRect&) {}
void clip(const Path&) {}
void scale(const FloatSize&) {}
void rotate(float) {}
@@ -63,7 +63,7 @@ public:
// On Windows, we need to update the HDC for form controls to draw in the right place.
void save();
void restore();
- void clip(const IntRect&);
+ void clip(const FloatRect&);
void clip(const Path&);
void scale(const FloatSize&);
void rotate(float);
@@ -71,9 +71,7 @@ public:
void concatCTM(const AffineTransform&);
void beginTransparencyLayer() { m_transparencyCount++; }
void endTransparencyLayer() { m_transparencyCount--; }
-#endif
-#if PLATFORM(WIN)
HDC m_hdc;
unsigned m_transparencyCount;
#endif
diff --git a/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/WebCore/platform/graphics/cg/ImageBufferCG.cpp
index 2d1ac01..502313b 100644
--- a/WebCore/platform/graphics/cg/ImageBufferCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageBufferCG.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 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
@@ -20,65 +21,69 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "ImageBuffer.h"
+#include "Base64.h"
+#include "BitmapImage.h"
+#include "CString.h"
#include "GraphicsContext.h"
-
+#include "ImageData.h"
+#include "MIMETypeRegistry.h"
+#include "PlatformString.h"
#include <ApplicationServices/ApplicationServices.h>
#include <wtf/Assertions.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/RetainPtr.h>
using namespace std;
namespace WebCore {
-auto_ptr<ImageBuffer> ImageBuffer::create(const IntSize& size, bool grayScale)
+ImageBufferData::ImageBufferData(const IntSize&)
+ : m_data(0)
{
+}
+
+ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
+ : m_data(size)
+ , m_size(size)
+{
+ success = false; // Make early return mean failure.
+ unsigned bytesPerRow;
if (size.width() < 0 || size.height() < 0)
- return auto_ptr<ImageBuffer>();
- unsigned int bytesPerRow = size.width();
+ return;
+ bytesPerRow = size.width();
if (!grayScale) {
// Protect against overflow
if (bytesPerRow > 0x3FFFFFFF)
- return auto_ptr<ImageBuffer>();
+ return;
bytesPerRow *= 4;
}
- void* imageBuffer = fastCalloc(size.height(), bytesPerRow);
- if (!imageBuffer)
- return auto_ptr<ImageBuffer>();
-
+ m_data.m_data = tryFastCalloc(size.height(), bytesPerRow);
+ ASSERT((reinterpret_cast<size_t>(m_data.m_data) & 2) == 0);
+
CGColorSpaceRef colorSpace = grayScale ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB();
- CGContextRef cgContext = CGBitmapContextCreate(imageBuffer, size.width(), size.height(), 8, bytesPerRow,
+ CGContextRef cgContext = CGBitmapContextCreate(m_data.m_data, size.width(), size.height(), 8, bytesPerRow,
colorSpace, grayScale ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
- if (!cgContext) {
- fastFree(imageBuffer);
- return auto_ptr<ImageBuffer>();
- }
+ if (!cgContext)
+ return;
- auto_ptr<GraphicsContext> context(new GraphicsContext(cgContext));
+ m_context.set(new GraphicsContext(cgContext));
+ m_context->scale(FloatSize(1, -1));
+ m_context->translate(0, -size.height());
CGContextRelease(cgContext);
-
- return auto_ptr<ImageBuffer>(new ImageBuffer(imageBuffer, size, context));
-}
-
-
-ImageBuffer::ImageBuffer(void* imageData, const IntSize& size, auto_ptr<GraphicsContext> context)
- : m_data(imageData)
- , m_size(size)
- , m_context(context.release())
- , m_cgImage(0)
-{
+ success = true;
}
ImageBuffer::~ImageBuffer()
{
- fastFree(m_data);
- CGImageRelease(m_cgImage);
+ fastFree(m_data.m_data);
}
GraphicsContext* ImageBuffer::context() const
@@ -86,16 +91,185 @@ GraphicsContext* ImageBuffer::context() const
return m_context.get();
}
-CGImageRef ImageBuffer::cgImage() const
+Image* ImageBuffer::image() const
{
- // It's assumed that if cgImage() is called, the actual rendering to the
- // contained GraphicsContext must be done, as we create the CGImageRef here.
- if (!m_cgImage) {
+ if (!m_image) {
+ // It's assumed that if image() is called, the actual rendering to the
+ // GraphicsContext must be done.
ASSERT(context());
- m_cgImage = CGBitmapContextCreateImage(context()->platformContext());
+ CGImageRef cgImage = CGBitmapContextCreateImage(context()->platformContext());
+ // BitmapImage will release the passed in CGImage on destruction
+ m_image = BitmapImage::create(cgImage);
+ }
+ return m_image.get();
+}
+
+PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
+{
+ PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height());
+ unsigned char* data = result->data()->data().data();
+
+ if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > m_size.width() || (rect.y() + rect.height()) > m_size.height())
+ memset(data, 0, result->data()->length());
+
+ int originx = rect.x();
+ int destx = 0;
+ if (originx < 0) {
+ destx = -originx;
+ originx = 0;
+ }
+ int endx = rect.x() + rect.width();
+ if (endx > m_size.width())
+ endx = m_size.width();
+ int numColumns = endx - originx;
+
+ int originy = rect.y();
+ int desty = 0;
+ if (originy < 0) {
+ desty = -originy;
+ originy = 0;
+ }
+ int endy = rect.y() + rect.height();
+ if (endy > m_size.height())
+ endy = m_size.height();
+ int numRows = endy - originy;
+
+ unsigned srcBytesPerRow = 4 * m_size.width();
+ unsigned destBytesPerRow = 4 * rect.width();
+
+ // ::create ensures that all ImageBuffers have valid data, so we don't need to check it here.
+ unsigned char* srcRows = reinterpret_cast<unsigned char*>(m_data.m_data) + originy * srcBytesPerRow + originx * 4;
+ unsigned char* destRows = data + desty * destBytesPerRow + destx * 4;
+ for (int y = 0; y < numRows; ++y) {
+ for (int x = 0; x < numColumns; x++) {
+ int basex = x * 4;
+ if (unsigned char alpha = srcRows[basex + 3]) {
+ destRows[basex] = (srcRows[basex] * 255) / alpha;
+ destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha;
+ destRows[basex + 2] = (srcRows[basex + 2] * 255) / alpha;
+ destRows[basex + 3] = alpha;
+ } else
+ reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0];
+ }
+ srcRows += srcBytesPerRow;
+ destRows += destBytesPerRow;
+ }
+ return result;
+}
+
+void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ ASSERT(sourceRect.width() > 0);
+ ASSERT(sourceRect.height() > 0);
+
+ int originx = sourceRect.x();
+ int destx = destPoint.x() + sourceRect.x();
+ ASSERT(destx >= 0);
+ ASSERT(destx < m_size.width());
+ ASSERT(originx >= 0);
+ ASSERT(originx <= sourceRect.right());
+
+ int endx = destPoint.x() + sourceRect.right();
+ ASSERT(endx <= m_size.width());
+
+ int numColumns = endx - destx;
+
+ int originy = sourceRect.y();
+ int desty = destPoint.y() + sourceRect.y();
+ ASSERT(desty >= 0);
+ ASSERT(desty < m_size.height());
+ ASSERT(originy >= 0);
+ ASSERT(originy <= sourceRect.bottom());
+
+ int endy = destPoint.y() + sourceRect.bottom();
+ ASSERT(endy <= m_size.height());
+ int numRows = endy - desty;
+
+ unsigned srcBytesPerRow = 4 * source->width();
+ unsigned destBytesPerRow = 4 * m_size.width();
+
+ unsigned char* srcRows = source->data()->data().data() + originy * srcBytesPerRow + originx * 4;
+ unsigned char* destRows = reinterpret_cast<unsigned char*>(m_data.m_data) + desty * destBytesPerRow + destx * 4;
+ for (int y = 0; y < numRows; ++y) {
+ for (int x = 0; x < numColumns; x++) {
+ int basex = x * 4;
+ unsigned char alpha = srcRows[basex + 3];
+ if (alpha != 255) {
+ destRows[basex] = (srcRows[basex] * alpha + 254) / 255;
+ destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255;
+ destRows[basex + 2] = (srcRows[basex + 2] * alpha + 254) / 255;
+ destRows[basex + 3] = alpha;
+ } else
+ reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0];
+ }
+ destRows += destBytesPerRow;
+ srcRows += srcBytesPerRow;
}
+}
+
+static RetainPtr<CFStringRef> utiFromMIMEType(const String& mimeType)
+{
+#if PLATFORM(MAC)
+ RetainPtr<CFStringRef> mimeTypeCFString(AdoptCF, mimeType.createCFString());
+ return RetainPtr<CFStringRef>(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeTypeCFString.get(), 0));
+#else
+ // FIXME: Add Windows support for all the supported UTIs when a way to convert from MIMEType to UTI reliably is found.
+ // For now, only support PNG, JPEG, and GIF. See <rdar://problem/6095286>.
+ static const CFStringRef kUTTypePNG = CFSTR("public.png");
+ static const CFStringRef kUTTypeJPEG = CFSTR("public.jpeg");
+ static const CFStringRef kUTTypeGIF = CFSTR("com.compuserve.gif");
- return m_cgImage;
+ if (equalIgnoringCase(mimeType, "image/png"))
+ return kUTTypePNG;
+ if (equalIgnoringCase(mimeType, "image/jpeg"))
+ return kUTTypeJPEG;
+ if (equalIgnoringCase(mimeType, "image/gif"))
+ return kUTTypeGIF;
+
+ ASSERT_NOT_REACHED();
+ return kUTTypePNG;
+#endif
}
+String ImageBuffer::toDataURL(const String& mimeType) const
+{
+ ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType));
+
+ RetainPtr<CGImageRef> image(AdoptCF, CGBitmapContextCreateImage(context()->platformContext()));
+ if (!image)
+ return "data:,";
+
+ size_t width = CGImageGetWidth(image.get());
+ size_t height = CGImageGetHeight(image.get());
+
+ OwnArrayPtr<uint32_t> imageData(new uint32_t[width * height]);
+ if (!imageData)
+ return "data:,";
+
+ RetainPtr<CGImageRef> transformedImage(AdoptCF, CGBitmapContextCreateImage(context()->platformContext()));
+ if (!transformedImage)
+ return "data:,";
+
+ RetainPtr<CFMutableDataRef> transformedImageData(AdoptCF, CFDataCreateMutable(kCFAllocatorDefault, 0));
+ if (!transformedImageData)
+ return "data:,";
+
+ RetainPtr<CGImageDestinationRef> imageDestination(AdoptCF, CGImageDestinationCreateWithData(transformedImageData.get(),
+ utiFromMIMEType(mimeType).get(), 1, 0));
+ if (!imageDestination)
+ return "data:,";
+
+ CGImageDestinationAddImage(imageDestination.get(), transformedImage.get(), 0);
+ CGImageDestinationFinalize(imageDestination.get());
+
+ Vector<char> in;
+ in.append(CFDataGetBytePtr(transformedImageData.get()), CFDataGetLength(transformedImageData.get()));
+
+ Vector<char> out;
+ base64Encode(in, out);
+ out.append('\0');
+
+ return String::format("data:%s;base64,%s", mimeType.utf8().data(), out.data());
}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/cg/ImageBufferData.h b/WebCore/platform/graphics/cg/ImageBufferData.h
new file mode 100644
index 0000000..5e6fc4c
--- /dev/null
+++ b/WebCore/platform/graphics/cg/ImageBufferData.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008 Google 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.
+ */
+
+#ifndef ImageBufferData_h
+#define ImageBufferData_h
+
+namespace WebCore {
+
+class IntSize;
+
+class ImageBufferData {
+public:
+ ImageBufferData(const IntSize&);
+
+ void* m_data;
+};
+
+} // namespace WebCore
+
+#endif // ImageBufferData_h
diff --git a/WebCore/platform/graphics/cg/ImageCG.cpp b/WebCore/platform/graphics/cg/ImageCG.cpp
index 5958d86..8609c46 100644
--- a/WebCore/platform/graphics/cg/ImageCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageCG.cpp
@@ -37,7 +37,7 @@
#include "PlatformString.h"
#include <ApplicationServices/ApplicationServices.h>
-#if PLATFORM(MAC)
+#if PLATFORM(MAC) || PLATFORM(CHROMIUM)
#include "WebCoreSystemInterface.h"
#endif
@@ -52,8 +52,9 @@ void FrameData::clear()
if (m_frame) {
CGImageRelease(m_frame);
m_frame = 0;
- m_duration = 0.0f;
- m_hasAlpha = true;
+ // NOTE: We purposefully don't reset metadata here, so that even if we
+ // throw away previously-decoded data, animation loops can still access
+ // properties like frame durations without re-decoding.
}
}
@@ -61,6 +62,37 @@ void FrameData::clear()
// Image Class
// ================================================
+BitmapImage::BitmapImage(CGImageRef cgImage, ImageObserver* observer)
+ : Image(observer)
+ , m_currentFrame(0)
+ , m_frames(0)
+ , m_frameTimer(0)
+ , m_repetitionCount(cAnimationNone)
+ , m_repetitionCountStatus(Unknown)
+ , m_repetitionsComplete(0)
+ , m_isSolidColor(false)
+ , m_animationFinished(true)
+ , m_allDataReceived(true)
+ , m_haveSize(true)
+ , m_sizeAvailable(true)
+ , m_decodedSize(0)
+ , m_haveFrameCount(true)
+ , m_frameCount(1)
+{
+ initPlatformData();
+
+ CGFloat width = CGImageGetWidth(cgImage);
+ CGFloat height = CGImageGetHeight(cgImage);
+ m_decodedSize = width * height * 4;
+ m_size = IntSize(width, height);
+
+ m_frames.grow(1);
+ m_frames[0].m_frame = cgImage;
+ m_frames[0].m_hasAlpha = true;
+ m_frames[0].m_haveMetadata = true;
+ checkForSolidColor();
+}
+
// Drawing Routines
void BitmapImage::checkForSolidColor()
@@ -97,78 +129,73 @@ CGImageRef BitmapImage::getCGImageRef()
return frameAtIndex(0);
}
-void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp)
+void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator compositeOp)
{
- if (!m_source.initialized())
- return;
-
- CGRect fr = ctxt->roundToDevicePixels(srcRect);
- CGRect ir = ctxt->roundToDevicePixels(dstRect);
+ startAnimation();
CGImageRef image = frameAtIndex(m_currentFrame);
if (!image) // If it's too early we won't have an image yet.
return;
if (mayFillWithSolidColor()) {
- fillWithSolidColor(ctxt, ir, solidColor(), compositeOp);
+ fillWithSolidColor(ctxt, destRect, solidColor(), compositeOp);
return;
}
- // Get the height (in adjusted, i.e. scaled, coords) of the portion of the image
- // that is currently decoded. This could be less that the actual height.
- CGSize selfSize = size(); // full image size, in pixels
- float curHeight = CGImageGetHeight(image); // height of loaded portion, in pixels
-
- CGSize adjustedSize = selfSize;
- if (curHeight < selfSize.height) {
- adjustedSize.height *= curHeight / selfSize.height;
-
- // Is the amount of available bands less than what we need to draw? If so,
- // we may have to clip 'fr' if it goes outside the available bounds.
- if (CGRectGetMaxY(fr) > adjustedSize.height) {
- float frHeight = adjustedSize.height - fr.origin.y; // clip fr to available bounds
- if (frHeight <= 0)
- return; // clipped out entirely
- ir.size.height *= (frHeight / fr.size.height); // scale ir proportionally to fr
- fr.size.height = frHeight;
- }
- }
+ float currHeight = CGImageGetHeight(image);
+ if (currHeight <= srcRect.y())
+ return;
CGContextRef context = ctxt->platformContext();
ctxt->save();
+ bool shouldUseSubimage = false;
+
+ // If the source rect is a subportion of the image, then we compute an inflated destination rect that will hold the entire image
+ // and then set a clip to the portion that we want to display.
+ FloatRect adjustedDestRect = destRect;
+ FloatSize selfSize = currentFrameSize();
+ if (srcRect.size() != selfSize) {
+ CGInterpolationQuality interpolationQuality = CGContextGetInterpolationQuality(context);
+ // When the image is scaled using high-quality interpolation, we create a temporary CGImage
+ // containing only the portion we want to display. We need to do this because high-quality
+ // interpolation smoothes sharp edges, causing pixels from outside the source rect to bleed
+ // into the destination rect. See <rdar://problem/6112909>.
+ shouldUseSubimage = (interpolationQuality == kCGInterpolationHigh || interpolationQuality == kCGInterpolationDefault) && srcRect.size() != destRect.size();
+ if (shouldUseSubimage) {
+ image = CGImageCreateWithImageInRect(image, srcRect);
+ if (currHeight < srcRect.bottom()) {
+ ASSERT(CGImageGetHeight(image) == currHeight - CGRectIntegral(srcRect).origin.y);
+ adjustedDestRect.setHeight(destRect.height() / srcRect.height() * CGImageGetHeight(image));
+ }
+ } else {
+ float xScale = srcRect.width() / destRect.width();
+ float yScale = srcRect.height() / destRect.height();
+
+ adjustedDestRect.setLocation(FloatPoint(destRect.x() - srcRect.x() / xScale, destRect.y() - srcRect.y() / yScale));
+ adjustedDestRect.setSize(FloatSize(selfSize.width() / xScale, selfSize.height() / yScale));
+
+ CGContextClipToRect(context, destRect);
+ }
+ }
+
+ // If the image is only partially loaded, then shrink the destination rect that we're drawing into accordingly.
+ if (!shouldUseSubimage && currHeight < selfSize.height())
+ adjustedDestRect.setHeight(adjustedDestRect.height() * currHeight / selfSize.height());
+
// Flip the coords.
ctxt->setCompositeOperation(compositeOp);
- CGContextTranslateCTM(context, ir.origin.x, ir.origin.y);
+ CGContextTranslateCTM(context, adjustedDestRect.x(), adjustedDestRect.bottom());
CGContextScaleCTM(context, 1, -1);
- CGContextTranslateCTM(context, 0, -ir.size.height);
-
- // Translated to origin, now draw at 0,0.
- ir.origin.x = ir.origin.y = 0;
-
- // If we're drawing a sub portion of the image then create
- // a image for the sub portion and draw that.
- // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
- if (fr.size.width != adjustedSize.width || fr.size.height != adjustedSize.height) {
- // Convert ft to image pixel coords:
- float xscale = adjustedSize.width / selfSize.width;
- float yscale = adjustedSize.height / curHeight; // yes, curHeight, not selfSize.height!
- fr.origin.x /= xscale;
- fr.origin.y /= yscale;
- fr.size.width /= xscale;
- fr.size.height /= yscale;
-
- image = CGImageCreateWithImageInRect(image, fr);
- if (image) {
- CGContextDrawImage(context, ir, image);
- CFRelease(image);
- }
- } else // Draw the whole image.
- CGContextDrawImage(context, ir, image);
-
+ adjustedDestRect.setLocation(FloatPoint());
+
+ // Draw the image.
+ CGContextDrawImage(context, adjustedDestRect, image);
+
+ if (shouldUseSubimage)
+ CGImageRelease(image);
+
ctxt->restore();
-
- startAnimation();
if (imageObserver())
imageObserver()->didDraw(this);
@@ -183,6 +210,9 @@ void Image::drawPatternCallback(void* info, CGContextRef context)
void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform,
const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect)
{
+ if (!nativeImageForCurrentFrame())
+ return;
+
ASSERT(patternTransform.isInvertible());
if (!patternTransform.isInvertible())
// Avoid a hang under CGContextDrawTiledImage on release builds.
@@ -192,9 +222,8 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const
ctxt->save();
CGContextClipToRect(context, destRect);
ctxt->setCompositeOperation(op);
- CGContextTranslateCTM(context, destRect.x(), destRect.y());
+ CGContextTranslateCTM(context, destRect.x(), destRect.y() + destRect.height());
CGContextScaleCTM(context, 1, -1);
- CGContextTranslateCTM(context, 0, -destRect.height());
// Compute the scaled tile size.
float scaledTileHeight = tileRect.height() * narrowPrecisionToFloat(patternTransform.d());
diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
index 2bfc204..73907c9 100644
--- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * 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
@@ -25,15 +25,17 @@
#include "config.h"
#include "ImageSource.h"
-#include "SharedBuffer.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)
{
@@ -52,15 +54,13 @@ void ImageSource::clear()
}
}
-const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32");
-
CFDictionaryRef imageSourceOptions()
{
static CFDictionaryRef options;
if (!options) {
- const void *keys[2] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32 };
- const void *values[2] = { kCFBooleanTrue, kCFBooleanTrue };
+ const void* keys[2] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32 };
+ const void* values[2] = { kCFBooleanTrue, kCFBooleanTrue };
options = CFDictionaryCreate(NULL, keys, values, 2,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
@@ -108,10 +108,10 @@ bool ImageSource::isSizeAvailable()
return result;
}
-IntSize ImageSource::size() const
+IntSize ImageSource::frameSizeAtIndex(size_t index) const
{
IntSize result;
- CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions());
+ CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions());
if (properties) {
int w = 0, h = 0;
CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth);
@@ -120,16 +120,23 @@ IntSize ImageSource::size() const
num = (CFNumberRef)CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight);
if (num)
CFNumberGetValue(num, kCFNumberIntType, &h);
- result = IntSize(w, 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) {
@@ -154,7 +161,23 @@ size_t ImageSource::frameCount() const
CGImageRef ImageSource::createFrameAtIndex(size_t index)
{
- return CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions());
+ 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)
@@ -164,6 +187,9 @@ bool ImageSource::frameIsCompleteAtIndex(size_t index)
float ImageSource::frameDurationAtIndex(size_t index)
{
+ if (!initialized())
+ return 0;
+
float duration = 0;
CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions());
if (properties) {
diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.h b/WebCore/platform/graphics/cg/PDFDocumentImage.h
index caddc05..5c9d4e1 100644
--- a/WebCore/platform/graphics/cg/PDFDocumentImage.h
+++ b/WebCore/platform/graphics/cg/PDFDocumentImage.h
@@ -38,14 +38,25 @@ namespace WebCore {
class PDFDocumentImage : public Image {
public:
- PDFDocumentImage();
+ static PassRefPtr<PDFDocumentImage> create()
+ {
+ return adoptRef(new PDFDocumentImage);
+ }
~PDFDocumentImage();
-
+
+ virtual bool hasSingleSecurityOrigin() const { return true; }
+
virtual bool dataChanged(bool allDataReceived);
+ // FIXME: PDF Images are underreporting decoded sizes and will be unable
+ // to prune because these functions are not implemented yet.
+ virtual void destroyDecodedData(bool incremental = false, bool preserveNearbyFrames = false) { }
+ virtual unsigned decodedSize() const { return 0; }
+
virtual IntSize size() const;
private:
+ PDFDocumentImage();
virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator);
void setCurrentPage(int);
diff --git a/WebCore/platform/graphics/cg/PathCG.cpp b/WebCore/platform/graphics/cg/PathCG.cpp
index c0a0caf..1382589 100644
--- a/WebCore/platform/graphics/cg/PathCG.cpp
+++ b/WebCore/platform/graphics/cg/PathCG.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
- * 2006 Rob Buis <buis@kde.org>
+ * 2006, 2008 Rob Buis <buis@kde.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -189,17 +189,17 @@ static void CGPathToCFStringApplierFunction(void* info, const CGPathElement *ele
CGPoint* points = element->points;
switch (element->type) {
case kCGPathElementMoveToPoint:
- CFStringAppendFormat(string, 0, CFSTR("M%.2f,%.2f"), points[0].x, points[0].y);
+ CFStringAppendFormat(string, 0, CFSTR("M%.2f,%.2f "), points[0].x, points[0].y);
break;
case kCGPathElementAddLineToPoint:
- CFStringAppendFormat(string, 0, CFSTR("L%.2f,%.2f"), points[0].x, points[0].y);
+ CFStringAppendFormat(string, 0, CFSTR("L%.2f,%.2f "), points[0].x, points[0].y);
break;
case kCGPathElementAddQuadCurveToPoint:
- CFStringAppendFormat(string, 0, CFSTR("Q%.2f,%.2f,%.2f,%.2f"),
+ CFStringAppendFormat(string, 0, CFSTR("Q%.2f,%.2f,%.2f,%.2f "),
points[0].x, points[0].y, points[1].x, points[1].y);
break;
case kCGPathElementAddCurveToPoint:
- CFStringAppendFormat(string, 0, CFSTR("C%.2f,%.2f,%.2f,%.2f,%.2f,%.2f"),
+ CFStringAppendFormat(string, 0, CFSTR("C%.2f,%.2f,%.2f,%.2f,%.2f,%.2f "),
points[0].x, points[0].y, points[1].x, points[1].y,
points[2].x, points[2].y);
break;
@@ -215,6 +215,8 @@ static CFStringRef CFStringFromCGPath(CGPathRef path)
CFMutableStringRef string = CFStringCreateMutable(NULL, 0);
CGPathApply(path, string, CGPathToCFStringApplierFunction);
+ CFStringTrimWhitespace(string);
+
return string;
}
diff --git a/WebCore/platform/graphics/cg/PatternCG.cpp b/WebCore/platform/graphics/cg/PatternCG.cpp
new file mode 100644
index 0000000..e1f7a69
--- /dev/null
+++ b/WebCore/platform/graphics/cg/PatternCG.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ *
+ * 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 "Pattern.h"
+
+#include "AffineTransform.h"
+#include "GraphicsContext.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+static void patternCallback(void* info, CGContextRef context)
+{
+ CGImageRef platformImage = static_cast<Image*>(info)->getCGImageRef();
+ if (!platformImage)
+ return;
+
+ CGRect rect = GraphicsContext(context).roundToDevicePixels(
+ FloatRect(0, 0, CGImageGetWidth(platformImage), CGImageGetHeight(platformImage)));
+ CGContextDrawImage(context, rect, platformImage);
+}
+
+static void patternReleaseCallback(void* info)
+{
+ static_cast<Image*>(info)->deref();
+}
+
+CGPatternRef Pattern::createPlatformPattern(const AffineTransform& transform) const
+{
+ IntRect tileRect = tileImage()->rect();
+
+ AffineTransform patternTransform = transform;
+ patternTransform.scale(1, -1);
+ patternTransform.translate(0, -tileRect.height());
+
+ // If FLT_MAX should also be used for xStep or yStep, nothing is rendered. Using fractions of FLT_MAX also
+ // result in nothing being rendered.
+ // INT_MAX is almost correct, but there seems to be some number wrapping occuring making the fill
+ // pattern is not filled correctly.
+ // So, just pick a really large number that works.
+ float xStep = m_repeatX ? tileRect.width() : (100000000.0f);
+ float yStep = m_repeatY ? tileRect.height() : (100000000.0f);
+
+ // The pattern will release the tile when it's done rendering in patternReleaseCallback
+ tileImage()->ref();
+
+ const CGPatternCallbacks patternCallbacks = { 0, patternCallback, patternReleaseCallback };
+ return CGPatternCreate(tileImage(), tileRect, patternTransform, xStep, yStep,
+ kCGPatternTilingConstantSpacing, TRUE, &patternCallbacks);
+}
+
+}