From 2fc2651226baac27029e38c9d6ef883fa32084db Mon Sep 17 00:00:00 2001 From: Steve Block Date: Wed, 18 May 2011 13:36:51 +0100 Subject: Merge WebKit at r78450: Initial merge by git. Change-Id: I6d3e5f1f868ec266a0aafdef66182ddc3f265dc1 --- .../platform/graphics/cg/GraphicsContext3DCG.cpp | 41 ++++++- .../platform/graphics/cg/GraphicsContextCG.cpp | 123 ++++++++++++++++++++- .../WebCore/platform/graphics/cg/ImageBufferCG.cpp | 14 +-- Source/WebCore/platform/graphics/cg/ImageCG.cpp | 4 +- 4 files changed, 162 insertions(+), 20 deletions(-) (limited to 'Source/WebCore/platform/graphics/cg') diff --git a/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp b/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp index c19bd72..187d296 100644 --- a/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp +++ b/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp @@ -26,7 +26,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) #include "GraphicsContext3D.h" #include "GraphicsContextCG.h" @@ -105,7 +105,7 @@ bool GraphicsContext3D::getImageData(Image* image, decoder.setData(image->data(), true); if (!decoder.frameCount()) return false; - decodedImage = decoder.createFrameAtIndex(0); + decodedImage.adoptCF(decoder.createFrameAtIndex(0)); cgImage = decodedImage.get(); } else cgImage = image->nativeImageForCurrentFrame(); @@ -116,6 +116,34 @@ bool GraphicsContext3D::getImageData(Image* image, size_t height = CGImageGetHeight(cgImage); if (!width || !height) return false; + + // See whether the image is using an indexed color space, and if + // so, re-render it into an RGB color space. The image re-packing + // code requires color data, not color table indices, for the + // image data. + CGColorSpaceRef colorSpace = CGImageGetColorSpace(cgImage); + CGColorSpaceModel model = CGColorSpaceGetModel(colorSpace); + if (model == kCGColorSpaceModelIndexed) { + RetainPtr bitmapContext; + // FIXME: we should probably manually convert the image by indexing into + // the color table, which would allow us to avoid premultiplying the + // alpha channel. Creation of a bitmap context with an alpha channel + // doesn't seem to work unless it's premultiplied. + bitmapContext.adoptCF(CGBitmapContextCreate(0, width, height, 8, width * 4, + deviceRGBColorSpaceRef(), + kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); + if (!bitmapContext) + return false; + + CGContextSetBlendMode(bitmapContext.get(), kCGBlendModeCopy); + CGContextSetInterpolationQuality(bitmapContext.get(), kCGInterpolationNone); + CGContextDrawImage(bitmapContext.get(), CGRectMake(0, 0, width, height), cgImage); + + // Now discard the original CG image and replace it with a copy from the bitmap context. + decodedImage.adoptCF(CGBitmapContextCreateImage(bitmapContext.get())); + cgImage = decodedImage.get(); + } + size_t bitsPerComponent = CGImageGetBitsPerComponent(cgImage); size_t bitsPerPixel = CGImageGetBitsPerPixel(cgImage); if (bitsPerComponent != 8 && bitsPerComponent != 16) @@ -168,10 +196,11 @@ bool GraphicsContext3D::getImageData(Image* image, AlphaFormat alphaFormat = AlphaFormatNone; switch (CGImageGetAlphaInfo(cgImage)) { case kCGImageAlphaPremultipliedFirst: - // This path is only accessible for MacOS earlier than 10.6.4. // This is a special case for texImage2D with HTMLCanvasElement input, - // in which case image->data() should be null. - ASSERT(!image->data()); + // in which case image->data() should be null, or indexed color models, + // where we need premultiplied alpha to create the bitmap context + // successfully. + ASSERT(!image->data() || model == kCGColorSpaceModelIndexed); if (!premultiplyAlpha) neededAlphaOp = AlphaDoUnmultiply; alphaFormat = AlphaFormatFirst; @@ -254,4 +283,4 @@ void GraphicsContext3D::paintToCanvas(const unsigned char* imagePixels, int imag } // namespace WebCore -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp index bcfc37b..3591479 100644 --- a/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -35,6 +35,7 @@ #include "KURL.h" #include "Path.h" #include "Pattern.h" +#include "ShadowBlur.h" #include #include @@ -165,9 +166,9 @@ void GraphicsContext::drawRect(const IntRect& rect) setCGFillColor(context, strokeColor(), strokeColorSpace()); CGRect rects[4] = { FloatRect(rect.x(), rect.y(), rect.width(), 1), - FloatRect(rect.x(), rect.bottom() - 1, rect.width(), 1), + FloatRect(rect.x(), rect.maxY() - 1, rect.width(), 1), FloatRect(rect.x(), rect.y() + 1, 1, rect.height() - 2), - FloatRect(rect.right() - 1, rect.y() + 1, 1, rect.height() - 2) + FloatRect(rect.maxX() - 1, rect.y() + 1, 1, rect.height() - 2) }; CGContextFillRects(context, rects, 4); if (oldFillColor != strokeColor()) @@ -563,7 +564,7 @@ void GraphicsContext::fillPath(const Path& path) CGContextClip(layerContext); m_state.fillGradient->paint(layerContext); - CGContextDrawLayerAtPoint(context, CGPointMake(rect.left(), rect.top()), layer); + CGContextDrawLayerAtPoint(context, CGPointMake(rect.x(), rect.y()), layer); CGLayerRelease(layer); } else { CGContextBeginPath(context); @@ -616,6 +617,16 @@ void GraphicsContext::strokePath(const Path& path) CGContextStrokePath(context); } +static float radiusToLegacyRadius(float radius) +{ + return radius > 8 ? 8 + 4 * sqrt((radius - 8) / 2) : radius; +} + +static bool hasBlurredShadow(const GraphicsContextState& state) +{ + return state.shadowColor.isValid() && state.shadowColor.alpha() && state.shadowBlur; +} + void GraphicsContext::fillRect(const FloatRect& rect) { if (paintingDisabled()) @@ -626,11 +637,16 @@ void GraphicsContext::fillRect(const FloatRect& rect) if (m_state.fillGradient) { CGContextSaveGState(context); if (hasShadow()) { - CGContextConcatCTM(context, m_state.fillGradient->gradientSpaceTransform()); CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(rect.width(), rect.height()), 0); CGContextRef layerContext = CGLayerGetContext(layer); + + CGContextTranslateCTM(layerContext, -rect.x(), -rect.y()); + CGContextAddRect(layerContext, rect); + CGContextClip(layerContext); + + CGContextConcatCTM(layerContext, m_state.fillGradient->gradientSpaceTransform()); m_state.fillGradient->paint(layerContext); - CGContextDrawLayerAtPoint(context, CGPointMake(rect.left(), rect.top()), layer); + CGContextDrawLayerAtPoint(context, CGPointMake(rect.x(), rect.y()), layer); CGLayerRelease(layer); } else { CGContextClipToRect(context, rect); @@ -643,7 +659,22 @@ void GraphicsContext::fillRect(const FloatRect& rect) if (m_state.fillPattern) applyFillPattern(); + + bool drawOwnShadow = hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; // Don't use ShadowBlur for canvas yet. + if (drawOwnShadow) { + float shadowBlur = m_state.shadowsUseLegacyRadius ? radiusToLegacyRadius(m_state.shadowBlur) : m_state.shadowBlur; + // Turn off CG shadows. + CGContextSaveGState(context); + CGContextSetShadowWithColor(platformContext(), CGSizeZero, 0, 0); + + ShadowBlur contextShadow(shadowBlur, m_state.shadowOffset, m_state.shadowColor, m_state.shadowColorSpace); + contextShadow.drawRectShadow(this, rect, RoundedIntRect::Radii()); + } + CGContextFillRect(context, rect); + + if (drawOwnShadow) + CGContextRestoreGState(context); } void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) @@ -658,7 +689,21 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorS if (oldFillColor != color || oldColorSpace != colorSpace) setCGFillColor(context, color, colorSpace); + bool drawOwnShadow = hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; // Don't use ShadowBlur for canvas yet. + if (drawOwnShadow) { + float shadowBlur = m_state.shadowsUseLegacyRadius ? radiusToLegacyRadius(m_state.shadowBlur) : m_state.shadowBlur; + // Turn off CG shadows. + CGContextSaveGState(context); + CGContextSetShadowWithColor(platformContext(), CGSizeZero, 0, 0); + + ShadowBlur contextShadow(shadowBlur, m_state.shadowOffset, m_state.shadowColor, m_state.shadowColorSpace); + contextShadow.drawRectShadow(this, rect, RoundedIntRect::Radii()); + } + CGContextFillRect(context, rect); + + if (drawOwnShadow) + CGContextRestoreGState(context); if (oldFillColor != color || oldColorSpace != colorSpace) setCGFillColor(context, oldFillColor, oldColorSpace); @@ -678,12 +723,72 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef Path path; path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight); + + bool drawOwnShadow = hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; // Don't use ShadowBlur for canvas yet. + if (drawOwnShadow) { + float shadowBlur = m_state.shadowsUseLegacyRadius ? radiusToLegacyRadius(m_state.shadowBlur) : m_state.shadowBlur; + + // Turn off CG shadows. + CGContextSaveGState(context); + CGContextSetShadowWithColor(platformContext(), CGSizeZero, 0, 0); + + ShadowBlur contextShadow(shadowBlur, m_state.shadowOffset, m_state.shadowColor, m_state.shadowColorSpace); + contextShadow.drawRectShadow(this, rect, RoundedIntRect::Radii(topLeft, topRight, bottomLeft, bottomRight)); + } + fillPath(path); + if (drawOwnShadow) + CGContextRestoreGState(context); + if (oldFillColor != color || oldColorSpace != colorSpace) setCGFillColor(context, oldFillColor, oldColorSpace); } +void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedIntRect& roundedHoleRect, const Color& color, ColorSpace colorSpace) +{ + if (paintingDisabled()) + return; + + CGContextRef context = platformContext(); + + Path path; + path.addRect(rect); + + if (!roundedHoleRect.radii().isZero()) + path.addRoundedRect(roundedHoleRect.rect(), roundedHoleRect.radii().topLeft(), roundedHoleRect.radii().topRight(), roundedHoleRect.radii().bottomLeft(), roundedHoleRect.radii().bottomRight()); + else + path.addRect(roundedHoleRect.rect()); + + WindRule oldFillRule = fillRule(); + Color oldFillColor = fillColor(); + ColorSpace oldFillColorSpace = fillColorSpace(); + + setFillRule(RULE_EVENODD); + setFillColor(color, colorSpace); + + // fillRectWithRoundedHole() assumes that the edges of rect are clipped out, so we only care about shadows cast around inside the hole. + bool drawOwnShadow = hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; + if (drawOwnShadow) { + float shadowBlur = m_state.shadowsUseLegacyRadius ? radiusToLegacyRadius(m_state.shadowBlur) : m_state.shadowBlur; + + // Turn off CG shadows. + CGContextSaveGState(context); + CGContextSetShadowWithColor(platformContext(), CGSizeZero, 0, 0); + + ShadowBlur contextShadow(shadowBlur, m_state.shadowOffset, m_state.shadowColor, m_state.shadowColorSpace); + contextShadow.drawInsetShadow(this, rect, roundedHoleRect.rect(), roundedHoleRect.radii()); + } + + fillPath(path); + + if (drawOwnShadow) + CGContextRestoreGState(context); + + setFillRule(oldFillRule); + setFillColor(oldFillColor, oldFillColorSpace); +} + void GraphicsContext::clip(const FloatRect& rect) { if (paintingDisabled()) @@ -722,6 +827,11 @@ void GraphicsContext::clipPath(const Path& path, WindRule clipRule) CGContextClip(context); } +IntRect GraphicsContext::clipBounds() const +{ + return enclosingIntRect(CGContextGetClipBoundingBox(platformContext())); +} + void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) { if (paintingDisabled()) @@ -766,6 +876,9 @@ void GraphicsContext::setPlatformShadow(const FloatSize& offset, float blur, con { if (paintingDisabled()) return; + + // FIXME: we could avoid the shadow setup cost when we know we'll render the shadow ourselves. + CGFloat xOffset = offset.width(); CGFloat yOffset = offset.height(); CGFloat blurRadius = blur; diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp index 295f632..ab5907e 100644 --- a/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp +++ b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp @@ -267,7 +267,7 @@ PassRefPtr getImageData(const IntRect& rect, const ImageBufferData& i RefPtr result = ByteArray::create(rect.width() * rect.height() * 4); unsigned char* data = result->data(); - if (rect.x() < 0 || rect.y() < 0 || rect.right() > size.width() || rect.bottom() > size.height()) + if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > size.width() || rect.maxY() > size.height()) memset(data, 0, result->length()); int originx = rect.x(); @@ -276,7 +276,7 @@ PassRefPtr getImageData(const IntRect& rect, const ImageBufferData& i destx = -originx; originx = 0; } - int endx = rect.right(); + int endx = rect.maxX(); if (endx > size.width()) endx = size.width(); int numColumns = endx - originx; @@ -287,7 +287,7 @@ PassRefPtr getImageData(const IntRect& rect, const ImageBufferData& i desty = -originy; originy = 0; } - int endy = rect.bottom(); + int endy = rect.maxY(); if (endy > size.height()) endy = size.height(); int numRows = endy - originy; @@ -377,9 +377,9 @@ void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& ASSERT(destx >= 0); ASSERT(destx < size.width()); ASSERT(originx >= 0); - ASSERT(originx <= sourceRect.right()); + ASSERT(originx <= sourceRect.maxX()); - int endx = destPoint.x() + sourceRect.right(); + int endx = destPoint.x() + sourceRect.maxX(); ASSERT(endx <= size.width()); int numColumns = endx - destx; @@ -389,9 +389,9 @@ void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& ASSERT(desty >= 0); ASSERT(desty < size.height()); ASSERT(originy >= 0); - ASSERT(originy <= sourceRect.bottom()); + ASSERT(originy <= sourceRect.maxY()); - int endy = destPoint.y() + sourceRect.bottom(); + int endy = destPoint.y() + sourceRect.maxY(); ASSERT(endy <= size.height()); int numRows = endy - desty; diff --git a/Source/WebCore/platform/graphics/cg/ImageCG.cpp b/Source/WebCore/platform/graphics/cg/ImageCG.cpp index dfee96a..08f65bd 100644 --- a/Source/WebCore/platform/graphics/cg/ImageCG.cpp +++ b/Source/WebCore/platform/graphics/cg/ImageCG.cpp @@ -204,7 +204,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const F adjustedDestRect.setHeight(subimageRect.height() / yScale); image.adoptCF(CGImageCreateWithImageInRect(image.get(), subimageRect)); - if (currHeight < srcRect.bottom()) { + if (currHeight < srcRect.maxY()) { ASSERT(CGImageGetHeight(image.get()) == currHeight - CGRectIntegral(srcRect).origin.y); adjustedDestRect.setHeight(CGImageGetHeight(image.get()) / yScale); } @@ -224,7 +224,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const F // Flip the coords. CGContextScaleCTM(context, 1, -1); - adjustedDestRect.setY(-adjustedDestRect.bottom()); + adjustedDestRect.setY(-adjustedDestRect.maxY()); // Adjust the color space. image = imageWithColorSpace(image.get(), styleColorSpace); -- cgit v1.1