Commit 71b3ce0c authored by bdash's avatar bdash
Browse files

2007-05-19 Mitz Pettel <mitz@webkit.org>

        Reviewed by Darin.

        - http://bugs.webkit.org/show_bug.cgi?id=13320
          rounded corners with drop shadows are really slow

        Test for a rendering bug fixed by this patch:
            fast/box-shadow/border-radius-big.html

        No test for the performance ingredient.

        * platform/graphics/GraphicsContext.cpp:
        (WebCore::GraphicsContext::addRoundedRectClip): Made cross-platform.
        Changed to use a single clipping path. If all the radii cannot be
        accommodated, clips to a rect.
        (WebCore::GraphicsContext::clipOutRoundedRect): Changed to use a single
        clipping path. If all the radii cannot be accommodated, clips out a rect.
        * platform/graphics/GraphicsContext.h: Added clipOut(const Path&).
        * platform/graphics/Path.cpp:
        (WebCore::Path::createRoundedRectangle): Added. Returns a rounded rectangle
        with the specified radii. If all the radii cannot be accommodated, returns
        a rectangular path.
        * platform/graphics/Path.h:
        * platform/graphics/cairo/GraphicsContextCairo.cpp:
        (WebCore::GraphicsContext::clipOut): Added.
        * platform/graphics/cg/GraphicsContextCG.cpp:
        (WebCore::GraphicsContext::fillRoundedRect): Changed to use a single path.
        (WebCore::GraphicsContext::clipOut): Added.
        * platform/graphics/qt/GraphicsContextQt.cpp:
        (WebCore::GraphicsContext::clipOut): Added.

2007-05-19  Mitz Pettel  <mitz@webkit.org>

        Reviewed by Darin.

        - http://bugs.webkit.org/show_bug.cgi?id=13320
          rounded corners with drop shadows are really slow

        * fast/box-shadow/border-radius-big-expected.checksum: Added.
        * fast/box-shadow/border-radius-big-expected.png: Added.
        * fast/box-shadow/border-radius-big-expected.txt: Added.
        * fast/box-shadow/border-radius-big.html: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@21601 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 44b89c45
2007-05-19 Mitz Pettel <mitz@webkit.org>
Reviewed by Darin.
- http://bugs.webkit.org/show_bug.cgi?id=13320
rounded corners with drop shadows are really slow
* fast/box-shadow/border-radius-big-expected.checksum: Added.
* fast/box-shadow/border-radius-big-expected.png: Added.
* fast/box-shadow/border-radius-big-expected.txt: Added.
* fast/box-shadow/border-radius-big.html: Added.
2007-05-19 Anders Carlsson <andersca@apple.com>
 
Reviewed by Mitz.
a108c69d9095386670389f4cfad7b255
\ No newline at end of file
layer at (0,0) size 800x600
RenderView at (0,0) size 800x600
layer at (0,0) size 800x600
RenderBlock {HTML} at (0,0) size 800x600
RenderBody {BODY} at (8,8) size 784x552
RenderBlock {P} at (0,0) size 784x18
RenderText {#text} at (0,0) size 32x18
text run at (0,0) width 32: "This:"
RenderBlock {DIV} at (40,58) size 60x60 [bgcolor=#008000]
RenderBlock {P} at (0,158) size 784x18
RenderText {#text} at (0,0) size 134x18
text run at (0,0) width 134: "Should look like this:"
RenderBlock {DIV} at (40,216) size 60x60 [bgcolor=#008000]
<p>
This:
</p>
<div style="margin: 40px; background: green; -webkit-border-radius: 40px; width: 60px; height: 60px; -webkit-box-shadow: black 10px 10px 0;"></div>
<p>
Should look like this:
</p>
<div style="margin: 40px; background: green; width: 60px; height: 60px; -webkit-box-shadow: black 10px 10px 0;"></div>
2007-05-19 Mitz Pettel <mitz@webkit.org>
Reviewed by Darin.
- http://bugs.webkit.org/show_bug.cgi?id=13320
rounded corners with drop shadows are really slow
Test for a rendering bug fixed by this patch:
fast/box-shadow/border-radius-big.html
No test for the performance ingredient.
* platform/graphics/GraphicsContext.cpp:
(WebCore::GraphicsContext::addRoundedRectClip): Made cross-platform.
Changed to use a single clipping path. If all the radii cannot be
accommodated, clips to a rect.
(WebCore::GraphicsContext::clipOutRoundedRect): Changed to use a single
clipping path. If all the radii cannot be accommodated, clips out a rect.
* platform/graphics/GraphicsContext.h: Added clipOut(const Path&).
* platform/graphics/Path.cpp:
(WebCore::Path::createRoundedRectangle): Added. Returns a rounded rectangle
with the specified radii. If all the radii cannot be accommodated, returns
a rectangular path.
* platform/graphics/Path.h:
* platform/graphics/cairo/GraphicsContextCairo.cpp:
(WebCore::GraphicsContext::clipOut): Added.
* platform/graphics/cg/GraphicsContextCG.cpp:
(WebCore::GraphicsContext::fillRoundedRect): Changed to use a single path.
(WebCore::GraphicsContext::clipOut): Added.
* platform/graphics/qt/GraphicsContextQt.cpp:
(WebCore::GraphicsContext::clipOut): Added.
2007-05-19 Anders Carlsson <andersca@apple.com>
 
Reviewed by Mitz.
......@@ -315,41 +315,22 @@ void GraphicsContext::drawTiledImage(Image* image, const IntRect& dest, const In
image->drawTiled(this, dest, srcRect, hRule, vRule, op);
}
void GraphicsContext::addRoundedRectClip(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
const IntSize& bottomLeft, const IntSize& bottomRight)
{
if (paintingDisabled())
return;
clip(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight));
}
void GraphicsContext::clipOutRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
const IntSize& bottomLeft, const IntSize& bottomRight)
{
if (paintingDisabled())
return;
// Need sufficient width and height to contain these curves. Sanity check our
// corner radii and our width/height values to make sure the curves can all fit.
if (static_cast<unsigned>(rect.width()) < static_cast<unsigned>(topLeft.width()) + static_cast<unsigned>(topRight.width()) ||
static_cast<unsigned>(rect.width()) < static_cast<unsigned>(bottomLeft.width()) + static_cast<unsigned>(bottomRight.width()) ||
static_cast<unsigned>(rect.height()) < static_cast<unsigned>(topLeft.height()) + static_cast<unsigned>(bottomLeft.height()) ||
static_cast<unsigned>(rect.height()) < static_cast<unsigned>(topRight.height()) + static_cast<unsigned>(bottomRight.height()))
return;
// Clip out each shape one by one.
clipOutEllipseInRect(IntRect(rect.x(), rect.y(), topLeft.width() * 2, topLeft.height() * 2));
clipOutEllipseInRect(IntRect(rect.right() - topRight.width() * 2, rect.y(), topRight.width() * 2, topRight.height() * 2));
clipOutEllipseInRect(IntRect(rect.x(), rect.bottom() - bottomLeft.height() * 2, bottomLeft.width() * 2, bottomLeft.height() * 2));
clipOutEllipseInRect(IntRect(rect.right() - bottomRight.width() * 2, rect.bottom() - bottomRight.height() * 2, bottomRight.width() * 2, bottomRight.height() * 2));
clipOut(IntRect(rect.x() + topLeft.width(), rect.y(),
rect.width() - topLeft.width() - topRight.width(),
max(topLeft.height(), topRight.height())));
clipOut(IntRect(rect.x() + bottomLeft.width(),
rect.bottom() - max(bottomLeft.height(), bottomRight.height()),
rect.width() - bottomLeft.width() - bottomRight.width(),
max(bottomLeft.height(), bottomRight.height())));
clipOut(IntRect(rect.x(), rect.y() + topLeft.height(),
max(topLeft.width(), bottomLeft.width()), rect.height() - topLeft.height() - bottomLeft.height()));
clipOut(IntRect(rect.right() - max(topRight.width(), bottomRight.width()),
rect.y() + topRight.height(),
max(topRight.width(), bottomRight.width()), rect.height() - topRight.height() - bottomRight.height()));
clipOut(IntRect(rect.x() + max(topLeft.width(), bottomLeft.width()),
rect.y() + max(topLeft.height(), topRight.height()),
rect.width() - max(topLeft.width(), bottomLeft.width()) - max(topRight.width(), bottomRight.width()),
rect.height() - max(topLeft.height(), topRight.height()) - max(bottomLeft.height(), bottomRight.height())));
clipOut(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight));
}
int GraphicsContext::textDrawingMode()
......
......@@ -177,9 +177,10 @@ namespace WebCore {
void setCompositeOperation(CompositeOperator);
void beginPath();
void addPath(const Path& path);
void addPath(const Path&);
void clip(const Path&);
void clipOut(const Path&);
void scale(const FloatSize&);
void rotate(float angleInRadians);
......
......@@ -158,6 +158,48 @@ Path Path::createRoundedRectangle(const FloatRect& rectangle, const FloatSize& r
return path;
}
Path Path::createRoundedRectangle(const FloatRect& rectangle, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius)
{
Path path;
float width = rectangle.width();
float height = rectangle.height();
if (width <= 0.0 || height <= 0.0)
return path;
if (width < topLeftRadius.width() + topRightRadius.width()
|| width < bottomLeftRadius.width() + bottomRightRadius.width()
|| height < topLeftRadius.height() + bottomLeftRadius.height()
|| height < topRightRadius.height() + bottomRightRadius.height())
// If all the radii cannot be accommodated, return a rect.
return createRectangle(rectangle);
float x = rectangle.x();
float y = rectangle.y();
path.moveTo(FloatPoint(x + topLeftRadius.width(), y));
path.addLineTo(FloatPoint(x + width - topRightRadius.width(), y));
path.addBezierCurveTo(FloatPoint(x + width - topRightRadius.width() * (1 - QUARTER), y), FloatPoint(x + width, y + topRightRadius.height() * (1 - QUARTER)), FloatPoint(x + width, y + topRightRadius.height()));
path.addLineTo(FloatPoint(x + width, y + height - bottomRightRadius.height()));
path.addBezierCurveTo(FloatPoint(x + width, y + height - bottomRightRadius.height() * (1 - QUARTER)), FloatPoint(x + width - bottomRightRadius.width() * (1 - QUARTER), y + height), FloatPoint(x + width - bottomRightRadius.width(), y + height));
path.addLineTo(FloatPoint(x + bottomLeftRadius.width(), y + height));
path.addBezierCurveTo(FloatPoint(x + bottomLeftRadius.width() * (1 - QUARTER), y + height), FloatPoint(x, y + height - bottomLeftRadius.height() * (1 - QUARTER)), FloatPoint(x, y + height - bottomLeftRadius.height()));
path.addLineTo(FloatPoint(x, y + topLeftRadius.height()));
path.addBezierCurveTo(FloatPoint(x, y + topLeftRadius.height() * (1 - QUARTER)), FloatPoint(x + topLeftRadius.width() * (1 - QUARTER), y), FloatPoint(x + topLeftRadius.width(), y));
path.closeSubpath();
return path;
}
Path Path::createRectangle(const FloatRect& rectangle)
{
Path path;
......
......@@ -103,6 +103,7 @@ namespace WebCore {
PlatformPath* platformPath() const { return m_path; }
static Path createRoundedRectangle(const FloatRect&, const FloatSize& roundingRadii);
static Path createRoundedRectangle(const FloatRect&, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius);
static Path createRectangle(const FloatRect&);
static Path createEllipse(const FloatPoint& center, float rx, float ry);
static Path createCircle(const FloatPoint& center, float r);
......
......@@ -548,12 +548,6 @@ void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
notImplemented();
}
void GraphicsContext::addRoundedRectClip(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
const IntSize& bottomLeft, const IntSize& bottomRight)
{
notImplemented();
}
void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
{
notImplemented();
......@@ -703,6 +697,11 @@ void GraphicsContext::clip(const Path&)
notImplemented();
}
void GraphicsContext::clipOut(const Path&)
{
notImplemented();
}
void GraphicsContext::rotate(float angle)
{
if (paintingDisabled())
......
......@@ -436,37 +436,9 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef
if (oldFillColor != color)
setCGFillColor(context, color);
// Add the four ellipses to the path. Technically this really isn't good enough, since we could end up
// not clipping the other 3/4 of the ellipse we don't care about. We're relying on the fact that for
// normal use cases these ellipses won't overlap one another (or when they do the curvature of one will
// be subsumed by the other).
CGContextAddEllipseInRect(context, CGRectMake(rect.x(), rect.y(), topLeft.width() * 2, topLeft.height() * 2));
CGContextAddEllipseInRect(context, CGRectMake(rect.right() - topRight.width() * 2, rect.y(),
topRight.width() * 2, topRight.height() * 2));
CGContextAddEllipseInRect(context, CGRectMake(rect.x(), rect.bottom() - bottomLeft.height() * 2,
bottomLeft.width() * 2, bottomLeft.height() * 2));
CGContextAddEllipseInRect(context, CGRectMake(rect.right() - bottomRight.width() * 2,
rect.bottom() - bottomRight.height() * 2,
bottomRight.width() * 2, bottomRight.height() * 2));
// Now add five rects (one for each edge rect in between the rounded corners and one for the interior).
CGContextAddRect(context, CGRectMake(rect.x() + topLeft.width(), rect.y(),
rect.width() - topLeft.width() - topRight.width(),
max(topLeft.height(), topRight.height())));
CGContextAddRect(context, CGRectMake(rect.x() + bottomLeft.width(),
rect.bottom() - max(bottomLeft.height(), bottomRight.height()),
rect.width() - bottomLeft.width() - bottomRight.width(),
max(bottomLeft.height(), bottomRight.height())));
CGContextAddRect(context, CGRectMake(rect.x(), rect.y() + topLeft.height(),
max(topLeft.width(), bottomLeft.width()), rect.height() - topLeft.height() - bottomLeft.height()));
CGContextAddRect(context, CGRectMake(rect.right() - max(topRight.width(), bottomRight.width()),
rect.y() + topRight.height(),
max(topRight.width(), bottomRight.width()), rect.height() - topRight.height() - bottomRight.height()));
CGContextAddRect(context, CGRectMake(rect.x() + max(topLeft.width(), bottomLeft.width()),
rect.y() + max(topLeft.height(), topRight.height()),
rect.width() - max(topLeft.width(), bottomLeft.width()) - max(topRight.width(), bottomRight.width()),
rect.height() - max(topLeft.height(), topRight.height()) - max(bottomLeft.height(), bottomRight.height())));
addPath(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight));
CGContextFillPath(context);
if (oldFillColor != color)
setCGFillColor(context, oldFillColor);
}
......@@ -502,59 +474,6 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& rect)
CGContextEOClip(platformContext());
}
void GraphicsContext::addRoundedRectClip(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
const IntSize& bottomLeft, const IntSize& bottomRight)
{
if (paintingDisabled())
return;
// Need sufficient width and height to contain these curves. Sanity check our
// corner radii and our width/height values to make sure the curves can all fit.
if (static_cast<unsigned>(rect.width()) < static_cast<unsigned>(topLeft.width()) + static_cast<unsigned>(topRight.width()) ||
static_cast<unsigned>(rect.width()) < static_cast<unsigned>(bottomLeft.width()) + static_cast<unsigned>(bottomRight.width()) ||
static_cast<unsigned>(rect.height()) < static_cast<unsigned>(topLeft.height()) + static_cast<unsigned>(bottomLeft.height()) ||
static_cast<unsigned>(rect.height()) < static_cast<unsigned>(topRight.height()) + static_cast<unsigned>(bottomRight.height()))
return;
// Clip to our rect.
clip(rect);
// OK, the curves can fit.
CGContextRef context = platformContext();
// Add the four ellipses to the path. Technically this really isn't good enough, since we could end up
// not clipping the other 3/4 of the ellipse we don't care about. We're relying on the fact that for
// normal use cases these ellipses won't overlap one another (or when they do the curvature of one will
// be subsumed by the other).
CGContextAddEllipseInRect(context, CGRectMake(rect.x(), rect.y(), topLeft.width() * 2, topLeft.height() * 2));
CGContextAddEllipseInRect(context, CGRectMake(rect.right() - topRight.width() * 2, rect.y(),
topRight.width() * 2, topRight.height() * 2));
CGContextAddEllipseInRect(context, CGRectMake(rect.x(), rect.bottom() - bottomLeft.height() * 2,
bottomLeft.width() * 2, bottomLeft.height() * 2));
CGContextAddEllipseInRect(context, CGRectMake(rect.right() - bottomRight.width() * 2,
rect.bottom() - bottomRight.height() * 2,
bottomRight.width() * 2, bottomRight.height() * 2));
// Now add five rects (one for each edge rect in between the rounded corners and one for the interior).
CGContextAddRect(context, CGRectMake(rect.x() + topLeft.width(), rect.y(),
rect.width() - topLeft.width() - topRight.width(),
max(topLeft.height(), topRight.height())));
CGContextAddRect(context, CGRectMake(rect.x() + bottomLeft.width(),
rect.bottom() - max(bottomLeft.height(), bottomRight.height()),
rect.width() - bottomLeft.width() - bottomRight.width(),
max(bottomLeft.height(), bottomRight.height())));
CGContextAddRect(context, CGRectMake(rect.x(), rect.y() + topLeft.height(),
max(topLeft.width(), bottomLeft.width()), rect.height() - topLeft.height() - bottomLeft.height()));
CGContextAddRect(context, CGRectMake(rect.right() - max(topRight.width(), bottomRight.width()),
rect.y() + topRight.height(),
max(topRight.width(), bottomRight.width()), rect.height() - topRight.height() - bottomRight.height()));
CGContextAddRect(context, CGRectMake(rect.x() + max(topLeft.width(), bottomLeft.width()),
rect.y() + max(topLeft.height(), topRight.height()),
rect.width() - max(topLeft.width(), bottomLeft.width()) - max(topRight.width(), bottomRight.width()),
rect.height() - max(topLeft.height(), topRight.height()) - max(bottomLeft.height(), bottomRight.height())));
CGContextClip(context);
}
void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
{
if (paintingDisabled())
......@@ -705,6 +624,17 @@ void GraphicsContext::clip(const Path& path)
m_data->clip(path);
}
void GraphicsContext::clipOut(const Path& path)
{
if (paintingDisabled())
return;
CGContextBeginPath(platformContext());
CGContextAddRect(platformContext(), CGContextGetClipBoundingBox(platformContext()));
CGContextAddPath(platformContext(), path.platformPath());
CGContextEOClip(platformContext());
}
void GraphicsContext::scale(const FloatSize& size)
{
if (paintingDisabled())
......
......@@ -723,6 +723,15 @@ void GraphicsContext::clip(const Path& path)
m_data->p().setClipPath(*path.platformPath());
}
void GraphicsContext::clipOut(const Path& path)
{
if (paintingDisabled())
return;
// FIXME: Implement
notImplemented();
}
void GraphicsContext::translate(float x, float y)
{
if (paintingDisabled())
......@@ -793,76 +802,6 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect,
m_data->p().setClipPath(path, Qt::IntersectClip);
}
void GraphicsContext::addRoundedRectClip(const IntRect& rect, const IntSize& topLeft,
const IntSize& topRight, const IntSize& bottomLeft,
const IntSize& bottomRight)
{
if (paintingDisabled())
return;
// Need sufficient width and height to contain these curves. Sanity check our top/bottom
// values and our width/height values to make sure the curves can all fit.
int requiredWidth = qMax(topLeft.width() + topRight.width(), bottomLeft.width() + bottomRight.width());
if (requiredWidth > rect.width())
return;
int requiredHeight = qMax(topLeft.height() + bottomLeft.height(), topRight.height() + bottomRight.height());
if (requiredHeight > rect.height())
return;
// Clip to our rect.
clip(rect);
// OK, the curves can fit.
QPainterPath path;
// Add the four ellipses to the path. Technically this really isn't good enough, since we could end up
// not clipping the other 3/4 of the ellipse we don't care about. We're relying on the fact that for
// normal use cases these ellipses won't overlap one another (or when they do the curvature of one will
// be subsumed by the other).
path.addEllipse(QRectF(rect.x(), rect.y(), topLeft.width() * 2, topLeft.height() * 2));
path.addEllipse(QRectF(rect.right() - topRight.width() * 2, rect.y(),
topRight.width() * 2, topRight.height() * 2));
path.addEllipse(QRectF(rect.x(), rect.bottom() - bottomLeft.height() * 2,
bottomLeft.width() * 2, bottomLeft.height() * 2));
path.addEllipse(QRectF(rect.right() - bottomRight.width() * 2,
rect.bottom() - bottomRight.height() * 2,
bottomRight.width() * 2, bottomRight.height() * 2));
int topLeftRightHeightMax = qMax(topLeft.height(), topRight.height());
int bottomLeftRightHeightMax = qMax(bottomLeft.height(), bottomRight.height());
int topBottomLeftWidthMax = qMax(topLeft.width(), bottomLeft.width());
int topBottomRightWidthMax = qMax(topRight.width(), bottomRight.width());
// Now add five rects (one for each edge rect in between the rounded corners and one for the interior).
path.addRect(QRectF(rect.x() + topLeft.width(),
rect.y(),
rect.width() - topLeft.width() - topRight.width(),
topLeftRightHeightMax));
path.addRect(QRectF(rect.x() + bottomLeft.width(), rect.bottom() - bottomLeftRightHeightMax,
rect.width() - bottomLeft.width() - bottomRight.width(), bottomLeftRightHeightMax));
path.addRect(QRectF(rect.x(),
rect.y() + topLeft.height(),
topBottomLeftWidthMax,
rect.height() - topLeft.height() - bottomLeft.height()));
path.addRect(QRectF(rect.right() - topBottomRightWidthMax,
rect.y() + topRight.height(),
topBottomRightWidthMax,
rect.height() - topRight.height() - bottomRight.height()));
path.addRect(QRectF(rect.x() + topBottomLeftWidthMax,
rect.y() + topLeftRightHeightMax,
rect.width() - topBottomLeftWidthMax - topBottomRightWidthMax,
rect.height() - topLeftRightHeightMax - bottomLeftRightHeightMax));
path.setFillRule(Qt::WindingFill);
m_data->p().setClipPath(path, Qt::IntersectClip);
}
void GraphicsContext::concatCTM(const AffineTransform& transform)
{
if (paintingDisabled())
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment