diff options
Diffstat (limited to 'Source/WebCore/platform/graphics/cg')
4 files changed, 136 insertions, 28 deletions
diff --git a/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp index 3591479..dbcab45 100644 --- a/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -65,6 +65,11 @@ #endif +// Undocumented CGContextSetCTM function, available at least since 10.4. +extern "C" { + CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform); +}; + using namespace std; namespace WebCore { @@ -603,12 +608,42 @@ void GraphicsContext::strokePath(const Path& path) CGContextAddPath(context, path.platformPath()); if (m_state.strokeGradient) { - CGContextSaveGState(context); - CGContextReplacePathWithStrokedPath(context); - CGContextClip(context); - CGContextConcatCTM(context, m_state.strokeGradient->gradientSpaceTransform()); - m_state.strokeGradient->paint(this); - CGContextRestoreGState(context); + if (hasShadow()) { + FloatRect rect = path.boundingRect(); + float lineWidth = strokeThickness(); + float doubleLineWidth = lineWidth * 2; + float layerWidth = ceilf(rect.width() + doubleLineWidth); + float layerHeight = ceilf(rect.height() + doubleLineWidth); + + CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(layerWidth, layerHeight), 0); + CGContextRef layerContext = CGLayerGetContext(layer); + CGContextSetLineWidth(layerContext, lineWidth); + + // Compensate for the line width, otherwise the layer's top-left corner would be + // aligned with the rect's top-left corner. This would result in leaving pixels out of + // the layer on the left and top sides. + float translationX = lineWidth - rect.x(); + float translationY = lineWidth - rect.y(); + CGContextTranslateCTM(layerContext, translationX, translationY); + + CGContextAddPath(layerContext, path.platformPath()); + CGContextReplacePathWithStrokedPath(layerContext); + CGContextClip(layerContext); + CGContextConcatCTM(layerContext, m_state.strokeGradient->gradientSpaceTransform()); + m_state.strokeGradient->paint(layerContext); + + float destinationX = roundf(rect.x() - lineWidth); + float destinationY = roundf(rect.y() - lineWidth); + CGContextDrawLayerAtPoint(context, CGPointMake(destinationX, destinationY), layer); + CGLayerRelease(layer); + } else { + CGContextSaveGState(context); + CGContextReplacePathWithStrokedPath(context); + CGContextClip(context); + CGContextConcatCTM(context, m_state.strokeGradient->gradientSpaceTransform()); + m_state.strokeGradient->paint(this); + CGContextRestoreGState(context); + } return; } @@ -952,7 +987,7 @@ void GraphicsContext::clearRect(const FloatRect& r) CGContextClearRect(platformContext(), r); } -void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth) +void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) { if (paintingDisabled()) return; @@ -960,19 +995,49 @@ void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth) CGContextRef context = platformContext(); if (m_state.strokeGradient) { - CGContextSaveGState(context); - setStrokeThickness(lineWidth); - CGContextAddRect(context, r); - CGContextReplacePathWithStrokedPath(context); - CGContextClip(context); - m_state.strokeGradient->paint(this); - CGContextRestoreGState(context); + if (hasShadow()) { + const float doubleLineWidth = lineWidth * 2; + const float layerWidth = ceilf(rect.width() + doubleLineWidth); + const float layerHeight = ceilf(rect.height() + doubleLineWidth); + CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(layerWidth, layerHeight), 0); + + CGContextRef layerContext = CGLayerGetContext(layer); + m_state.strokeThickness = lineWidth; + CGContextSetLineWidth(layerContext, lineWidth); + + // Compensate for the line width, otherwise the layer's top-left corner would be + // aligned with the rect's top-left corner. This would result in leaving pixels out of + // the layer on the left and top sides. + const float translationX = lineWidth - rect.x(); + const float translationY = lineWidth - rect.y(); + CGContextTranslateCTM(layerContext, translationX, translationY); + + CGContextAddRect(layerContext, rect); + CGContextReplacePathWithStrokedPath(layerContext); + CGContextClip(layerContext); + CGContextConcatCTM(layerContext, m_state.strokeGradient->gradientSpaceTransform()); + m_state.strokeGradient->paint(layerContext); + + const float destinationX = roundf(rect.x() - lineWidth); + const float destinationY = roundf(rect.y() - lineWidth); + CGContextDrawLayerAtPoint(context, CGPointMake(destinationX, destinationY), layer); + CGLayerRelease(layer); + } else { + CGContextSaveGState(context); + setStrokeThickness(lineWidth); + CGContextAddRect(context, rect); + CGContextReplacePathWithStrokedPath(context); + CGContextClip(context); + CGContextConcatCTM(context, m_state.strokeGradient->gradientSpaceTransform()); + m_state.strokeGradient->paint(this); + CGContextRestoreGState(context); + } return; } if (m_state.strokePattern) applyStrokePattern(); - CGContextStrokeRectWithWidth(context, r, lineWidth); + CGContextStrokeRectWithWidth(context, rect, lineWidth); } void GraphicsContext::setLineCap(LineCap cap) @@ -1085,6 +1150,15 @@ void GraphicsContext::concatCTM(const AffineTransform& transform) m_data->m_userToDeviceTransformKnownToBeIdentity = false; } +void GraphicsContext::setCTM(const AffineTransform& transform) +{ + if (paintingDisabled()) + return; + CGContextSetCTM(platformContext(), transform); + m_data->setCTM(transform); + m_data->m_userToDeviceTransformKnownToBeIdentity = false; +} + AffineTransform GraphicsContext::getCTM() const { CGAffineTransform t = CGContextGetCTM(platformContext()); @@ -1130,7 +1204,7 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin); } -void GraphicsContext::drawLineForText(const IntPoint& point, int width, bool printing) +void GraphicsContext::drawLineForText(const FloatPoint& point, float width, bool printing) { if (paintingDisabled()) return; @@ -1269,6 +1343,16 @@ void GraphicsContext::setAllowsFontSmoothing(bool allowsFontSmoothing) #endif } +void GraphicsContext::setIsCALayerContext(bool) +{ + m_data->m_isCALayerContext = true; +} + +bool GraphicsContext::isCALayerContext() const +{ + return m_data->m_isCALayerContext; +} + void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode) { if (paintingDisabled()) diff --git a/Source/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h b/Source/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h index d4fa32e..f9255df 100644 --- a/Source/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h +++ b/Source/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h @@ -33,7 +33,7 @@ namespace WebCore { class GraphicsContextPlatformPrivate { public: - GraphicsContextPlatformPrivate(CGContextRef cgContext) + GraphicsContextPlatformPrivate(CGContextRef cgContext, bool isLayerContext = false) : m_cgContext(cgContext) #if PLATFORM(WIN) , m_hdc(0) @@ -41,6 +41,7 @@ public: , m_shouldIncludeChildWindows(false) #endif , m_userToDeviceTransformKnownToBeIdentity(false) + , m_isCALayerContext(isLayerContext) { } @@ -59,6 +60,7 @@ public: void rotate(float) {} void translate(float, float) {} void concatCTM(const AffineTransform&) {} + void setCTM(const AffineTransform&) {} void beginTransparencyLayer() {} void endTransparencyLayer() {} #endif @@ -74,6 +76,7 @@ public: void rotate(float); void translate(float, float); void concatCTM(const AffineTransform&); + void setCTM(const AffineTransform&); void beginTransparencyLayer() { m_transparencyCount++; } void endTransparencyLayer() { m_transparencyCount--; } @@ -84,6 +87,7 @@ public: RetainPtr<CGContextRef> m_cgContext; bool m_userToDeviceTransformKnownToBeIdentity; + bool m_isCALayerContext; }; } diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp index ab5907e..7c8e313 100644 --- a/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp +++ b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp @@ -244,21 +244,21 @@ void ImageBuffer::drawPattern(GraphicsContext* destContext, const FloatRect& src } } -void ImageBuffer::clip(GraphicsContext* context, const FloatRect& rect) const +void ImageBuffer::clip(GraphicsContext* contextToClip, const FloatRect& rect) const { - CGContextRef platformContext = context->platformContext(); + CGContextRef platformContextToClip = contextToClip->platformContext(); RetainPtr<CGImageRef> image; if (!m_accelerateRendering) image.adoptCF(cgImage(m_size, m_data)); #if USE(IOSURFACE_CANVAS_BACKING_STORE) else - image.adoptCF(wkIOSurfaceContextCreateImage(platformContext)); + image.adoptCF(wkIOSurfaceContextCreateImage(context()->platformContext())); #endif - CGContextTranslateCTM(platformContext, rect.x(), rect.y() + rect.height()); - CGContextScaleCTM(platformContext, 1, -1); - CGContextClipToMask(platformContext, FloatRect(FloatPoint(), rect.size()), image.get()); - CGContextScaleCTM(platformContext, 1, -1); - CGContextTranslateCTM(platformContext, -rect.x(), -rect.y() - rect.height()); + CGContextTranslateCTM(platformContextToClip, rect.x(), rect.y() + rect.height()); + CGContextScaleCTM(platformContextToClip, 1, -1); + CGContextClipToMask(platformContextToClip, FloatRect(FloatPoint(), rect.size()), image.get()); + CGContextScaleCTM(platformContextToClip, 1, -1); + CGContextTranslateCTM(platformContextToClip, -rect.x(), -rect.y() - rect.height()); } template <Multiply multiplied> diff --git a/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp index 4ed8684..068ea5b 100644 --- a/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp +++ b/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp @@ -40,7 +40,12 @@ using namespace std; namespace WebCore { -static const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32"); +const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32"); + +// kCGImagePropertyGIFUnclampedDelayTime is available in the ImageIO framework headers on some versions +// of SnowLeopard. It's not possible to detect whether the constant is available so we define our own here +// that won't conflict with ImageIO's version when it is available. +const CFStringRef WebCoreCGImagePropertyGIFUnclampedDelayTime = CFSTR("UnclampedDelayTime"); #if !PLATFORM(MAC) size_t sharedBufferGetBytesAtPosition(void* info, void* buffer, off_t position, size_t count) @@ -222,6 +227,17 @@ bool ImageSource::getHotSpot(IntPoint& hotSpot) const return true; } +size_t ImageSource::bytesDecodedToDetermineProperties() const +{ + // Measured by tracing malloc/calloc calls on Mac OS 10.6.6, x86_64. + // A non-zero value ensures cached images with no decoded frames still enter + // the live decoded resources list when the CGImageSource decodes image + // properties, allowing the cache to prune the partially decoded image. + // This value is likely to be inaccurate on other platforms, but the overall + // behavior is unchanged. + return 13088; +} + int ImageSource::repetitionCount() { int result = cAnimationLoopOnce; // No property means loop once. @@ -301,9 +317,13 @@ float ImageSource::frameDurationAtIndex(size_t index) if (properties) { CFDictionaryRef typeProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary); if (typeProperties) { - CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(typeProperties, kCGImagePropertyGIFDelayTime); - if (num) + if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(typeProperties, WebCoreCGImagePropertyGIFUnclampedDelayTime)) { + // Use the unclamped frame delay if it exists. + CFNumberGetValue(num, kCFNumberFloatType, &duration); + } else if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(typeProperties, kCGImagePropertyGIFDelayTime)) { + // Fall back to the clamped frame delay if the unclamped frame delay does not exist. CFNumberGetValue(num, kCFNumberFloatType, &duration); + } } } |