Skip to content
Permalink
Browse files
2010-08-19 Alejandro G. Castro <alex@igalia.com>
        Reviewed by Dirk Schulze.

        [GTK] The size of the shadow image uses the standard deviation
        size instead of the blur radius
        https://bugs.webkit.org/show_bug.cgi?id=40793

        The kernelSize variable was renamed to radius and recalculated
        considering the CSS3 specification
        http://www.w3.org/TR/css3-background/#the-box-shadow, and the
        visual result of other browsers. The HTML5 canvas shadow standard
        deviation calculation that was used, was not appropiate for the
        blur distance specified in the CSS3.

        * platform/graphics/GraphicsContext.h:
        * platform/graphics/cairo/FontCairo.cpp:
        (WebCore::Font::drawGlyphs):
        * platform/graphics/cairo/GraphicsContextCairo.cpp:
        (WebCore::GraphicsContext::calculateShadowBufferDimensions):
        Changed the calculation, now we use the parameter in the style
        directly as recomended in the CSS3 standard.
        (WebCore::drawPathShadow):
        (WebCore::drawBorderlessRectShadow):
        (WebCore::GraphicsContext::createPlatformShadow): We get the
        standard deviation from the radius using the new function and we
        create the filter with that deviation.
        * platform/graphics/cairo/ImageCairo.cpp:
        (WebCore::BitmapImage::draw):
        * platform/graphics/filters/FEGaussianBlur.cpp:
        (WebCore::FEGaussianBlur::calculateStdDeviation):  Added this
        function that gets the standard deviation from the blur
        radius. Required in the CSS3 case where we have this radio and we
        need the deviation to initialize the algorithm.
        * platform/graphics/filters/FEGaussianBlur.h:

Canonical link: https://commits.webkit.org/56441@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@65661 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
alexgcastro committed Aug 19, 2010
1 parent 6f6a2e9 commit 73e962ee24c4b8abf1b4836f67079b92b849b725
@@ -1,3 +1,39 @@
2010-08-19 Alejandro G. Castro <alex@igalia.com>

Reviewed by Dirk Schulze.

[GTK] The size of the shadow image uses the standard deviation
size instead of the blur radius
https://bugs.webkit.org/show_bug.cgi?id=40793

The kernelSize variable was renamed to radius and recalculated
considering the CSS3 specification
http://www.w3.org/TR/css3-background/#the-box-shadow, and the
visual result of other browsers. The HTML5 canvas shadow standard
deviation calculation that was used, was not appropiate for the
blur distance specified in the CSS3.

* platform/graphics/GraphicsContext.h:
* platform/graphics/cairo/FontCairo.cpp:
(WebCore::Font::drawGlyphs):
* platform/graphics/cairo/GraphicsContextCairo.cpp:
(WebCore::GraphicsContext::calculateShadowBufferDimensions):
Changed the calculation, now we use the parameter in the style
directly as recomended in the CSS3 standard.
(WebCore::drawPathShadow):
(WebCore::drawBorderlessRectShadow):
(WebCore::GraphicsContext::createPlatformShadow): We get the
standard deviation from the radius using the new function and we
create the filter with that deviation.
* platform/graphics/cairo/ImageCairo.cpp:
(WebCore::BitmapImage::draw):
* platform/graphics/filters/FEGaussianBlur.cpp:
(WebCore::FEGaussianBlur::calculateStdDeviation): Added this
function that gets the standard deviation from the blur
radius. Required in the CSS3 case where we have this radio and we
need the deviation to initialize the algorithm.
* platform/graphics/filters/FEGaussianBlur.h:

2010-08-19 Andreas Kling <andreas.kling@nokia.com>

Reviewed by Kenneth Rohde Christiansen.
@@ -294,8 +294,8 @@ namespace WebCore {
void setAlpha(float);
#if PLATFORM(CAIRO)
float getAlpha();
void createPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float kernelSize);
static void calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& kernelSize, const FloatRect& sourceRect, const FloatSize& shadowSize, float shadowBlur);
void createPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float radius);
static void calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& radius, const FloatRect& sourceRect, const FloatSize& shadowSize, float shadowBlur);
#endif

void setCompositeOperation(CompositeOperator);
@@ -94,15 +94,15 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons
FloatRect rect(FloatPoint(), FloatSize(extents.width, extents.height));
IntSize shadowBufferSize;
FloatRect shadowRect;
float kernelSize = 0.f;
GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur);
float radius = 0;
context->calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, rect, shadowSize, shadowBlur);

// Draw shadow into a new ImageBuffer
OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize);
GraphicsContext* shadowContext = shadowBuffer->context();
cairo_t* shadowCr = shadowContext->platformContext();

cairo_translate(shadowCr, kernelSize, extents.height + kernelSize);
cairo_translate(shadowCr, radius, extents.height + radius);

cairo_set_scaled_font(shadowCr, font->platformData().scaledFont());
cairo_show_glyphs(shadowCr, glyphs, numGlyphs);
@@ -113,7 +113,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons
cairo_restore(shadowCr);
}
cairo_translate(cr, 0.0, -extents.height);
context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize);
context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius);
#else
cairo_translate(cr, shadowSize.width(), shadowSize.height());
cairo_show_glyphs(cr, glyphs, numGlyphs);
@@ -61,6 +61,8 @@
#include "GraphicsContextPlatformPrivateCairo.h"
#include "GraphicsContextPrivate.h"

using namespace std;

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
@@ -173,18 +175,17 @@ static void addConvexPolygonToContext(cairo_t* context, size_t numPoints, const
cairo_close_path(context);
}

void GraphicsContext::calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& kernelSize, const FloatRect& sourceRect, const FloatSize& shadowSize, float shadowBlur)
void GraphicsContext::calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& radius, const FloatRect& sourceRect, const FloatSize& shadowSize, float shadowBlur)
{
#if ENABLE(FILTERS)
// calculate the kernel size according to the HTML5 canvas shadow specification
kernelSize = (shadowBlur < 8 ? shadowBlur / 2.f : sqrt(shadowBlur * 2.f));
int blurRadius = ceil(kernelSize);
// limit radius to 128
radius = min(128.f, max(shadowBlur, 0.f));

shadowBufferSize = IntSize(sourceRect.width() + blurRadius * 2, sourceRect.height() + blurRadius * 2);
shadowBufferSize = IntSize(sourceRect.width() + radius * 2, sourceRect.height() + radius * 2);

// determine dimensions of shadow rect
shadowRect = FloatRect(sourceRect.location(), shadowBufferSize);
shadowRect.move(shadowSize.width() - kernelSize, shadowSize.height() - kernelSize);
shadowRect.move(shadowSize.width() - radius, shadowSize.height() - radius);
#endif
}

@@ -209,16 +210,16 @@ static inline void drawPathShadow(GraphicsContext* context, GraphicsContextPriva

IntSize shadowBufferSize;
FloatRect shadowRect;
float kernelSize = 0;
GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur);
float radius = 0;
GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, rect, shadowSize, shadowBlur);

// Create suitably-sized ImageBuffer to hold the shadow.
OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize);

// Draw shadow into a new ImageBuffer.
cairo_t* shadowContext = shadowBuffer->context()->platformContext();
copyContextProperties(cr, shadowContext);
cairo_translate(shadowContext, -rect.x() + kernelSize, -rect.y() + kernelSize);
cairo_translate(shadowContext, -rect.x() + radius, -rect.y() + radius);
cairo_new_path(shadowContext);
cairo_append_path(shadowContext, path);

@@ -227,7 +228,7 @@ static inline void drawPathShadow(GraphicsContext* context, GraphicsContextPriva
if (strokeShadow)
setPlatformStroke(context, shadowContext, gcp);

context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize);
context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius);
#endif
}

@@ -631,15 +632,15 @@ static void drawBorderlessRectShadow(GraphicsContext* context, const FloatRect&

IntSize shadowBufferSize;
FloatRect shadowRect;
float kernelSize = 0;
GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur);
float radius = 0;
GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, rect, shadowSize, shadowBlur);

// Draw shadow into a new ImageBuffer
OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize);
GraphicsContext* shadowContext = shadowBuffer->context();
shadowContext->fillRect(FloatRect(FloatPoint(kernelSize, kernelSize), rect.size()), rectColor, DeviceColorSpace);
shadowContext->fillRect(FloatRect(FloatPoint(radius, radius), rect.size()), rectColor, DeviceColorSpace);

context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize);
context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius);
#endif
}

@@ -920,28 +921,28 @@ void GraphicsContext::setPlatformShadow(FloatSize const& size, float, Color cons
}
}

void GraphicsContext::createPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float kernelSize)
void GraphicsContext::createPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float radius)
{
#if ENABLE(FILTERS)
cairo_t* cr = m_data->cr;

// draw the shadow without blurring, if kernelSize is zero
if (!kernelSize) {
// calculate the standard deviation
float sd = FEGaussianBlur::calculateStdDeviation(radius);

// draw the shadow without blurring, if radius is zero
if (!radius || !sd) {
setColor(cr, shadowColor);
cairo_mask_surface(cr, buffer->m_data.m_surface, shadowRect.x(), shadowRect.y());
return;
}

// limit kernel size to 1000, this is what CG is doing.
kernelSize = std::min(1000.f, kernelSize);

// create filter
RefPtr<Filter> filter = ImageBufferFilter::create();
filter->setSourceImage(buffer);
RefPtr<FilterEffect> source = SourceGraphic::create();
source->setScaledSubRegion(FloatRect(FloatPoint(), shadowRect.size()));
source->setIsAlphaImage(true);
RefPtr<FilterEffect> blur = FEGaussianBlur::create(source.get(), kernelSize, kernelSize);
RefPtr<FilterEffect> blur = FEGaussianBlur::create(source.get(), sd, sd);
blur->setScaledSubRegion(FloatRect(FloatPoint(), shadowRect.size()));
blur->apply(filter.get());

@@ -141,8 +141,8 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo
if (context->getShadow(shadowSize, shadowBlur, shadowColor)) {
IntSize shadowBufferSize;
FloatRect shadowRect;
float kernelSize (0.0);
GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, dstRect, shadowSize, shadowBlur);
float radius = 0;
context->calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, dstRect, shadowSize, shadowBlur);
shadowColor = colorWithOverrideAlpha(shadowColor.rgb(), (shadowColor.alpha() * context->getAlpha()) / 255.f);

//draw shadow into a new ImageBuffer
@@ -153,7 +153,7 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo
cairo_rectangle(shadowContext, 0, 0, dstRect.width(), dstRect.height());
cairo_fill(shadowContext);

context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize);
context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius);
}
#endif

@@ -200,6 +200,12 @@ TextStream& FEGaussianBlur::externalRepresentation(TextStream& ts, int indent) c
return ts;
}

float FEGaussianBlur::calculateStdDeviation(float radius)
{
// Blur radius represents 2/3 times the kernel size, the dest pixel is half of the radius applied 3 times
return max((radius * 2 / 3.f - 0.5f) / gGaussianKernelFactor, 0.f);
}

} // namespace WebCore

#endif // ENABLE(FILTERS)
@@ -43,6 +43,8 @@ class FEGaussianBlur : public FilterEffect {
void dump();
TextStream& externalRepresentation(TextStream&, int indent) const;

static float calculateStdDeviation(float);

private:
FEGaussianBlur(FilterEffect*, const float&, const float&);
static void kernelPosition(int boxBlur, unsigned& std, int& dLeft, int& dRight);

0 comments on commit 73e962e

Please sign in to comment.