[skia] Track a simple opaque area when painting via PlatformContextSkia and...

[skia] Track a simple opaque area when painting via PlatformContextSkia and save in LayerTextureUpdater
https://bugs.webkit.org/show_bug.cgi?id=74352

Patch by Dana Jansens <danakj@chromium.org> on 2012-01-12
Reviewed by Stephen White.

Source/WebCore:

New unit tests in PlatformContextSkiaTest.cpp

* WebCore.gypi:
* platform/graphics/skia/GraphicsContextSkia.cpp:
(WebCore::GraphicsContext::clearRect):
(WebCore::GraphicsContext::drawConvexPolygon):
(WebCore::GraphicsContext::drawEllipse):
(WebCore::drawOuterPath):
(WebCore::drawInnerPath):
(WebCore::GraphicsContext::drawFocusRing):
(WebCore::GraphicsContext::drawLine):
(WebCore::GraphicsContext::drawLineForTextChecking):
(WebCore::GraphicsContext::drawLineForText):
(WebCore::GraphicsContext::fillPath):
(WebCore::GraphicsContext::fillRect):
(WebCore::GraphicsContext::fillRoundedRect):
(WebCore::GraphicsContext::strokeArc):
(WebCore::GraphicsContext::strokePath):
(WebCore::GraphicsContext::strokeRect):
* platform/graphics/skia/ImageSkia.cpp:
(WebCore::paintSkBitmap):
* platform/graphics/skia/OpaqueRegionSkia.cpp: Added.
(WebCore::OpaqueRegionSkia::OpaqueRegionSkia):
(WebCore::OpaqueRegionSkia::~OpaqueRegionSkia):
(WebCore::OpaqueRegionSkia::asRect):
(WebCore::xfermodeIsOpaque):
(WebCore::xfermodePreservesOpaque):
(WebCore::paintIsOpaque):
(WebCore::OpaqueRegionSkia::didDrawRect):
(WebCore::OpaqueRegionSkia::didDrawPath):
(WebCore::OpaqueRegionSkia::didDrawPoints):
(WebCore::OpaqueRegionSkia::didDrawBounded):
(WebCore::OpaqueRegionSkia::didDraw):
(WebCore::OpaqueRegionSkia::didDrawUnbounded):
(WebCore::OpaqueRegionSkia::markRectAsOpaque):
(WebCore::OpaqueRegionSkia::markRectAsNonOpaque):
* platform/graphics/skia/OpaqueRegionSkia.h: Added.
* platform/graphics/skia/PlatformContextSkia.cpp:
(WebCore::PlatformContextSkia::PlatformContextSkia):
(WebCore::PlatformContextSkia::clippedToImage):
(WebCore::PlatformContextSkia::drawRect):
(WebCore::PlatformContextSkia::paintSkPaint):
(WebCore::PlatformContextSkia::didDrawRect):
(WebCore::PlatformContextSkia::didDrawPath):
(WebCore::PlatformContextSkia::didDrawPoints):
(WebCore::PlatformContextSkia::didDrawBounded):
* platform/graphics/skia/PlatformContextSkia.h:
(WebCore::PlatformContextSkia::setTrackOpaqueRegion):
(WebCore::PlatformContextSkia::opaqueRegion):

Source/WebKit/chromium:

* WebKit.gypi:
* tests/PlatformContextSkiaTest.cpp: Added.
(WebCore::TEST):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@104861 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 3d8eaf44
2012-01-12 Dana Jansens <danakj@chromium.org>
[skia] Track a simple opaque area when painting via PlatformContextSkia and save in LayerTextureUpdater
https://bugs.webkit.org/show_bug.cgi?id=74352
Reviewed by Stephen White.
New unit tests in PlatformContextSkiaTest.cpp
* WebCore.gypi:
* platform/graphics/skia/GraphicsContextSkia.cpp:
(WebCore::GraphicsContext::clearRect):
(WebCore::GraphicsContext::drawConvexPolygon):
(WebCore::GraphicsContext::drawEllipse):
(WebCore::drawOuterPath):
(WebCore::drawInnerPath):
(WebCore::GraphicsContext::drawFocusRing):
(WebCore::GraphicsContext::drawLine):
(WebCore::GraphicsContext::drawLineForTextChecking):
(WebCore::GraphicsContext::drawLineForText):
(WebCore::GraphicsContext::fillPath):
(WebCore::GraphicsContext::fillRect):
(WebCore::GraphicsContext::fillRoundedRect):
(WebCore::GraphicsContext::strokeArc):
(WebCore::GraphicsContext::strokePath):
(WebCore::GraphicsContext::strokeRect):
* platform/graphics/skia/ImageSkia.cpp:
(WebCore::paintSkBitmap):
* platform/graphics/skia/OpaqueRegionSkia.cpp: Added.
(WebCore::OpaqueRegionSkia::OpaqueRegionSkia):
(WebCore::OpaqueRegionSkia::~OpaqueRegionSkia):
(WebCore::OpaqueRegionSkia::asRect):
(WebCore::xfermodeIsOpaque):
(WebCore::xfermodePreservesOpaque):
(WebCore::paintIsOpaque):
(WebCore::OpaqueRegionSkia::didDrawRect):
(WebCore::OpaqueRegionSkia::didDrawPath):
(WebCore::OpaqueRegionSkia::didDrawPoints):
(WebCore::OpaqueRegionSkia::didDrawBounded):
(WebCore::OpaqueRegionSkia::didDraw):
(WebCore::OpaqueRegionSkia::didDrawUnbounded):
(WebCore::OpaqueRegionSkia::markRectAsOpaque):
(WebCore::OpaqueRegionSkia::markRectAsNonOpaque):
* platform/graphics/skia/OpaqueRegionSkia.h: Added.
* platform/graphics/skia/PlatformContextSkia.cpp:
(WebCore::PlatformContextSkia::PlatformContextSkia):
(WebCore::PlatformContextSkia::clippedToImage):
(WebCore::PlatformContextSkia::drawRect):
(WebCore::PlatformContextSkia::paintSkPaint):
(WebCore::PlatformContextSkia::didDrawRect):
(WebCore::PlatformContextSkia::didDrawPath):
(WebCore::PlatformContextSkia::didDrawPoints):
(WebCore::PlatformContextSkia::didDrawBounded):
* platform/graphics/skia/PlatformContextSkia.h:
(WebCore::PlatformContextSkia::setTrackOpaqueRegion):
(WebCore::PlatformContextSkia::opaqueRegion):
2012-01-12 Beth Dakin <bdakin@apple.com>
https://bugs.webkit.org/show_bug.cgi?id=76209
......@@ -3928,6 +3928,8 @@
'platform/graphics/skia/IntRectSkia.cpp',
'platform/graphics/skia/NativeImageSkia.cpp',
'platform/graphics/skia/NativeImageSkia.h',
'platform/graphics/skia/OpaqueRegionSkia.cpp',
'platform/graphics/skia/OpaqueRegionSkia.h',
'platform/graphics/skia/PathSkia.cpp',
'platform/graphics/skia/PatternSkia.cpp',
'platform/graphics/skia/PlatformContextSkia.cpp',
......
......@@ -339,6 +339,7 @@ void GraphicsContext::clearRect(const FloatRect& rect)
platformContext()->setupPaintForFilling(&paint);
paint.setXfermodeMode(SkXfermode::kClear_Mode);
platformContext()->canvas()->drawRect(r, paint);
platformContext()->didDrawRect(r, paint);
}
void GraphicsContext::clip(const FloatRect& rect)
......@@ -473,11 +474,13 @@ void GraphicsContext::drawConvexPolygon(size_t numPoints,
platformContext()->setupPaintForFilling(&paint);
paint.setAntiAlias(shouldAntialias);
platformContext()->canvas()->drawPath(path, paint);
platformContext()->didDrawPath(path, paint);
if (strokeStyle() != NoStroke) {
paint.reset();
platformContext()->setupPaintForStroking(&paint, 0, 0);
platformContext()->canvas()->drawPath(path, paint);
platformContext()->didDrawPath(path, paint);
}
}
......@@ -513,11 +516,13 @@ void GraphicsContext::drawEllipse(const IntRect& elipseRect)
SkPaint paint;
platformContext()->setupPaintForFilling(&paint);
platformContext()->canvas()->drawOval(rect, paint);
platformContext()->didDrawBounded(rect, paint);
if (strokeStyle() != NoStroke) {
paint.reset();
platformContext()->setupPaintForStroking(&paint, &rect, 0);
platformContext()->canvas()->drawOval(rect, paint);
platformContext()->didDrawBounded(rect, paint);
}
}
......@@ -526,7 +531,7 @@ void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, con
// FIXME: implement
}
static inline void drawOuterPath(SkCanvas* canvas, const SkPath& path, SkPaint& paint, int width)
static inline void drawOuterPath(PlatformContextSkia* context, const SkPath& path, SkPaint& paint, int width)
{
#if PLATFORM(CHROMIUM) && OS(DARWIN)
paint.setAlpha(64);
......@@ -536,15 +541,17 @@ static inline void drawOuterPath(SkCanvas* canvas, const SkPath& path, SkPaint&
paint.setStrokeWidth(1);
paint.setPathEffect(new SkCornerPathEffect(1))->unref();
#endif
canvas->drawPath(path, paint);
context->canvas()->drawPath(path, paint);
context->didDrawPath(path, paint);
}
static inline void drawInnerPath(SkCanvas* canvas, const SkPath& path, SkPaint& paint, int width)
static inline void drawInnerPath(PlatformContextSkia* context, const SkPath& path, SkPaint& paint, int width)
{
#if PLATFORM(CHROMIUM) && OS(DARWIN)
paint.setAlpha(128);
paint.setStrokeWidth(width * 0.5f);
canvas->drawPath(path, paint);
context->canvas()->drawPath(path, paint);
context->didDrawPath(path, paint);
#endif
}
......@@ -581,9 +588,8 @@ void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int
paint.setColor(color.rgb());
focusRingRegion.getBoundaryPath(&path);
SkCanvas* canvas = platformContext()->canvas();
drawOuterPath(canvas, path, paint, width);
drawInnerPath(canvas, path, paint, width);
drawOuterPath(platformContext(), path, paint, width);
drawInnerPath(platformContext(), path, paint, width);
}
// This is only used to draw borders.
......@@ -631,12 +637,15 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
fillPaint.setColor(paint.getColor());
platformContext()->canvas()->drawRect(r1, fillPaint);
platformContext()->canvas()->drawRect(r2, fillPaint);
platformContext()->didDrawRect(r1, fillPaint);
platformContext()->didDrawRect(r2, fillPaint);
}
adjustLineToPixelBoundaries(p1, p2, width, penStyle);
SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 };
platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint);
platformContext()->didDrawPoints(SkCanvas::kLines_PointMode, 2, pts, paint);
}
void GraphicsContext::drawLineForTextChecking(const FloatPoint& pt, float width, TextCheckingLineStyle style)
......@@ -712,6 +721,7 @@ void GraphicsContext::drawLineForTextChecking(const FloatPoint& pt, float width,
originX + WebCoreFloatToSkScalar(width),
originY + SkIntToScalar(misspellBitmap->height()));
platformContext()->canvas()->drawRect(rect, paint);
platformContext()->didDrawRect(rect, paint);
}
void GraphicsContext::drawLineForText(const FloatPoint& pt,
......@@ -736,6 +746,7 @@ void GraphicsContext::drawLineForText(const FloatPoint& pt,
// Text lines are drawn using the stroke color.
paint.setColor(platformContext()->effectiveStrokeColor());
platformContext()->canvas()->drawRect(r, paint);
platformContext()->didDrawRect(r, paint);
}
// Draws a filled rectangle with a stroked border.
......@@ -770,6 +781,7 @@ void GraphicsContext::fillPath(const Path& pathToFill)
platformContext()->setupPaintForFilling(&paint);
platformContext()->canvas()->drawPath(path, paint);
platformContext()->didDrawPath(path, paint);
}
void GraphicsContext::fillRect(const FloatRect& rect)
......@@ -788,6 +800,7 @@ void GraphicsContext::fillRect(const FloatRect& rect)
SkPaint paint;
platformContext()->setupPaintForFilling(&paint);
platformContext()->canvas()->drawRect(r, paint);
platformContext()->didDrawRect(r, paint);
platformContext()->restore();
}
......@@ -816,6 +829,7 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorS
platformContext()->setupPaintCommon(&paint);
paint.setColor(color.rgb());
platformContext()->canvas()->drawRect(r, paint);
platformContext()->didDrawRect(r, paint);
}
void GraphicsContext::fillRoundedRect(const IntRect& rect,
......@@ -855,6 +869,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect,
platformContext()->setupPaintForFilling(&paint);
paint.setColor(color.rgb());
platformContext()->canvas()->drawPath(path, paint);
platformContext()->didDrawPath(path, paint);
}
AffineTransform GraphicsContext::getCTM() const
......@@ -1139,6 +1154,7 @@ void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan)
if (!isPathSkiaSafe(getCTM(), path))
return;
platformContext()->canvas()->drawPath(path, paint);
platformContext()->didDrawPath(path, paint);
}
void GraphicsContext::strokePath(const Path& pathToStroke)
......@@ -1153,6 +1169,7 @@ void GraphicsContext::strokePath(const Path& pathToStroke)
SkPaint paint;
platformContext()->setupPaintForStroking(&paint, 0, 0);
platformContext()->canvas()->drawPath(path, paint);
platformContext()->didDrawPath(path, paint);
}
void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
......@@ -1173,9 +1190,10 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
bool validW = r.width() > 0;
bool validH = r.height() > 0;
SkCanvas* canvas = platformContext()->canvas();
if (validW && validH)
if (validW && validH) {
canvas->drawRect(r, paint);
else if (validW || validH) {
platformContext()->didDrawRect(r, paint);
} else if (validW || validH) {
// we are expected to respect the lineJoin, so we can't just call
// drawLine -- we have to create a path that doubles back on itself.
SkPath path;
......@@ -1183,6 +1201,7 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
path.lineTo(r.fRight, r.fBottom);
path.close();
canvas->drawPath(path, paint);
platformContext()->didDrawPath(path, paint);
}
}
......
......@@ -248,6 +248,7 @@ static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImag
// we don't send extra pixels.
canvas->drawBitmapRect(bitmap.bitmap(), &srcRect, destRect, &paint);
}
platformContext->didDrawRect(destRect, paint, &bitmap.bitmap());
}
// Transforms the given dimensions with the given matrix. Used to see how big
......
/*
* Copyright (c) 2012, 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:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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 THE COPYRIGHT
* OWNER 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 "OpaqueRegionSkia.h"
#include "PlatformContextSkia.h"
#include "SkShader.h"
namespace WebCore {
OpaqueRegionSkia::OpaqueRegionSkia()
: m_opaqueRect(SkRect::MakeEmpty())
{
}
OpaqueRegionSkia::~OpaqueRegionSkia()
{
}
IntRect OpaqueRegionSkia::asRect() const
{
// Returns the largest enclosed rect.
int left = SkScalarCeil(m_opaqueRect.fLeft);
int top = SkScalarCeil(m_opaqueRect.fTop);
int right = SkScalarFloor(m_opaqueRect.fRight);
int bottom = SkScalarFloor(m_opaqueRect.fBottom);
return IntRect(left, top, right-left, bottom-top);
}
// Returns true if the xfermode will force the dst to be opaque, regardless of the current dst.
static inline bool xfermodeIsOpaque(const SkPaint& paint, bool srcIsOpaque)
{
if (!srcIsOpaque)
return false;
SkXfermode* xfermode = paint.getXfermode();
if (!xfermode)
return true; // default to kSrcOver_Mode
SkXfermode::Mode mode;
if (!xfermode->asMode(&mode))
return false;
switch (mode) {
case SkXfermode::kSrc_Mode: // source
case SkXfermode::kSrcOver_Mode: // source + dest - source*dest
case SkXfermode::kDstOver_Mode: // source + dest - source*dest
case SkXfermode::kDstATop_Mode: // source
case SkXfermode::kPlus_Mode: // source+dest
default: // the rest are all source + dest - source*dest
return true;
case SkXfermode::kClear_Mode: // 0
case SkXfermode::kDst_Mode: // dest
case SkXfermode::kSrcIn_Mode: // source * dest
case SkXfermode::kDstIn_Mode: // dest * source
case SkXfermode::kSrcOut_Mode: // source * (1-dest)
case SkXfermode::kDstOut_Mode: // dest * (1-source)
case SkXfermode::kSrcATop_Mode: // dest
case SkXfermode::kXor_Mode: // source + dest - 2*(source*dest)
return false;
}
}
// Returns true if the xfermode will keep the dst opaque, assuming the dst is already opaque.
static inline bool xfermodePreservesOpaque(const SkPaint& paint, bool srcIsOpaque)
{
SkXfermode* xfermode = paint.getXfermode();
if (!xfermode)
return true; // default to kSrcOver_Mode
SkXfermode::Mode mode;
if (!xfermode->asMode(&mode))
return false;
switch (mode) {
case SkXfermode::kDst_Mode: // dest
case SkXfermode::kSrcOver_Mode: // source + dest - source*dest
case SkXfermode::kDstOver_Mode: // source + dest - source*dest
case SkXfermode::kSrcATop_Mode: // dest
case SkXfermode::kPlus_Mode: // source+dest
default: // the rest are all source + dest - source*dest
return true;
case SkXfermode::kClear_Mode: // 0
case SkXfermode::kSrcOut_Mode: // source * (1-dest)
case SkXfermode::kDstOut_Mode: // dest * (1-source)
case SkXfermode::kXor_Mode: // source + dest - 2*(source*dest)
return false;
case SkXfermode::kSrc_Mode: // source
case SkXfermode::kSrcIn_Mode: // source * dest
case SkXfermode::kDstIn_Mode: // dest * source
case SkXfermode::kDstATop_Mode: // source
return srcIsOpaque;
}
}
// Returns true if all pixels painted will be opaque.
static inline bool paintIsOpaque(const SkPaint& paint, const SkBitmap* bitmap = 0, bool checkFillOnly = false)
{
if (paint.getAlpha() < 0xFF)
return false;
if (!checkFillOnly && paint.getStyle() != SkPaint::kFill_Style && paint.isAntiAlias())
return false;
SkShader* shader = paint.getShader();
if (shader && !shader->isOpaque())
return false;
if (bitmap && !bitmap->isOpaque())
return false;
return true;
}
void OpaqueRegionSkia::didDrawRect(const PlatformContextSkia* context, const SkRect& fillRect, const SkPaint& paint, const SkBitmap* bitmap)
{
// Any stroking may put alpha in pixels even if the filling part does not.
if (paint.getStyle() != SkPaint::kFill_Style) {
bool opaque = paintIsOpaque(paint, bitmap);
bool fillsBounds = false;
if (!paint.canComputeFastBounds())
didDrawUnbounded(paint, opaque);
else {
SkRect strokeRect;
strokeRect = paint.computeFastBounds(fillRect, &strokeRect);
didDraw(context, strokeRect, paint, opaque, fillsBounds);
}
}
bool checkFillOnly = true;
bool opaque = paintIsOpaque(paint, bitmap, checkFillOnly);
bool fillsBounds = paint.getStyle() != SkPaint::kStroke_Style;
didDraw(context, fillRect, paint, opaque, fillsBounds);
}
void OpaqueRegionSkia::didDrawPath(const PlatformContextSkia* context, const SkPath& path, const SkPaint& paint)
{
SkRect rect;
if (path.isRect(&rect)) {
didDrawRect(context, rect, paint, 0);
return;
}
bool opaque = paintIsOpaque(paint);
bool fillsBounds = false;
if (!paint.canComputeFastBounds())
didDrawUnbounded(paint, opaque);
else {
rect = paint.computeFastBounds(path.getBounds(), &rect);
didDraw(context, rect, paint, opaque, fillsBounds);
}
}
void OpaqueRegionSkia::didDrawPoints(const PlatformContextSkia* context, SkCanvas::PointMode mode, int numPoints, const SkPoint points[], const SkPaint& paint)
{
if (!numPoints)
return;
SkRect rect;
rect.fLeft = points[0].fX;
rect.fRight = points[0].fX + 1;
rect.fTop = points[0].fY;
rect.fBottom = points[0].fY + 1;
for (int i = 1; i < numPoints; ++i) {
rect.fLeft = std::min(rect.fLeft, points[i].fX);
rect.fRight = std::max(rect.fRight, points[i].fX + 1);
rect.fTop = std::min(rect.fTop, points[i].fY);
rect.fBottom = std::max(rect.fBottom, points[i].fY + 1);
}
bool opaque = paintIsOpaque(paint);
bool fillsBounds = false;
if (!paint.canComputeFastBounds())
didDrawUnbounded(paint, opaque);
else {
rect = paint.computeFastBounds(rect, &rect);
didDraw(context, rect, paint, opaque, fillsBounds);
}
}
void OpaqueRegionSkia::didDrawBounded(const PlatformContextSkia* context, const SkRect& bounds, const SkPaint& paint)
{
bool opaque = paintIsOpaque(paint);
bool fillsBounds = false;
if (!paint.canComputeFastBounds())
didDrawUnbounded(paint, opaque);
else {
SkRect rect;
rect = paint.computeFastBounds(bounds, &rect);
didDraw(context, rect, paint, opaque, fillsBounds);
}
}
void OpaqueRegionSkia::didDraw(const PlatformContextSkia* context, const SkRect& rect, const SkPaint& paint, bool drawsOpaque, bool fillsBounds)
{
if (fillsBounds && xfermodeIsOpaque(paint, drawsOpaque))
markRectAsOpaque(context, rect);
else if (SkRect::Intersects(rect, m_opaqueRect) && !xfermodePreservesOpaque(paint, drawsOpaque))
markRectAsNonOpaque(rect);
}
void OpaqueRegionSkia::didDrawUnbounded(const SkPaint& paint, bool drawsOpaque)
{
if (!xfermodePreservesOpaque(paint, drawsOpaque)) {
// We don't know what was drawn on so just destroy the known opaque area.
m_opaqueRect = SkRect::MakeEmpty();
}
}
void OpaqueRegionSkia::markRectAsOpaque(const PlatformContextSkia* context, const SkRect& rect)
{
// We want to keep track of an opaque region but bound its complexity at a constant size.
// We keep track of the largest rectangle seen by area. If we can add the new rect to this
// rectangle then we do that, as that is the cheapest way to increase the area returned
// without increasing the complexity.
if (rect.isEmpty())
return;
if (!context->clippedToImage().isOpaque())
return;
if (m_opaqueRect.contains(rect))
return;
if (rect.contains(m_opaqueRect)) {
m_opaqueRect = rect;
return;
}
if (rect.fTop <= m_opaqueRect.fTop && rect.fBottom >= m_opaqueRect.fBottom) {
if (rect.fLeft < m_opaqueRect.fLeft && rect.fRight >= m_opaqueRect.fLeft)
m_opaqueRect.fLeft = rect.fLeft;
if (rect.fRight > m_opaqueRect.fRight && rect.fLeft <= m_opaqueRect.fRight)
m_opaqueRect.fRight = rect.fRight;
} else if (rect.fLeft <= m_opaqueRect.fLeft && rect.fRight >= m_opaqueRect.fRight) {
if (rect.fTop < m_opaqueRect.fTop && rect.fBottom >= m_opaqueRect.fTop)
m_opaqueRect.fTop = rect.fTop;
if (rect.fBottom > m_opaqueRect.fBottom && rect.fTop <= m_opaqueRect.fBottom)
m_opaqueRect.fBottom = rect.fBottom;
}
long opaqueArea = (long)m_opaqueRect.width() * (long)m_opaqueRect.height();
long area = (long)rect.width() * (long)rect.height();
if (area > opaqueArea)
m_opaqueRect = rect;
}
void OpaqueRegionSkia::markRectAsNonOpaque(const SkRect& rect)
{
// We want to keep as much of the current opaque rectangle as we can, so find the one largest
// rectangle inside m_opaqueRect that does not intersect with |rect|.
if (rect.contains(m_opaqueRect)) {
m_opaqueRect.setEmpty();
return;
}
int deltaLeft = rect.fLeft - m_opaqueRect.fLeft;
int deltaRight = m_opaqueRect.fRight - rect.fRight;
int deltaTop = rect.fTop - m_opaqueRect.fTop;
int deltaBottom = m_opaqueRect.fBottom - rect.fBottom;
// horizontal is the larger of the two rectangles to the left or to the right of |rect| and inside m_opaqueRect.
// vertical is the larger of the two rectangles above or below |rect| and inside m_opaqueRect.
SkRect horizontal = m_opaqueRect;
if (deltaTop > deltaBottom)
horizontal.fBottom = rect.fTop;
else
horizontal.fTop = rect.fBottom;
SkRect vertical = m_opaqueRect;
if (deltaLeft > deltaRight)
vertical.fRight = rect.fLeft;
else
vertical.fLeft = rect.fRight;
if ((long)horizontal.width() * (long)horizontal.height() > (long)vertical.width() * (long)vertical.height())
m_opaqueRect = horizontal;
else
m_opaqueRect = vertical;
}
} // namespace WebCore
/*
* Copyright (c) 2012, 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:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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 THE COPYRIGHT
* OWNER 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 OpaqueRegionSkia_h
#define OpaqueRegionSkia_h
#include "IntRect.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkPaint.h"
#include "SkPoint.h"
#include "SkRect.h"
namespace WebCore {
class PlatformContextSkia;
// This class is an encapsulation of functionality for PlatformContextSkia, and its methods are mirrored
// there for the outside world. It tracks paints and computes what area will be opaque.
class OpaqueRegionSkia {
public:
OpaqueRegionSkia();
virtual ~OpaqueRegionSkia();