mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 544099 - Highly optimise -moz-box-shadow for common cases by allowing layout to specify an area where blurring is not needed r=roc,joe
--HG-- rename : gfx/thebes/src/gfxBlur.cpp => gfx/src/thebes/utils/gfxBlur.cpp rename : gfx/thebes/public/gfxBlur.h => gfx/src/thebes/utils/gfxBlur.h extra : rebase_source : d7ad7a1ee2ac9e25937133dba95f0f8d7347d612
This commit is contained in:
parent
b5f0594b55
commit
3e049f0588
@ -1586,7 +1586,7 @@ nsCanvasRenderingContext2D::ShadowInitialize(const gfxRect& extents, gfxAlphaBox
|
||||
blurRadius.height, blurRadius.width);
|
||||
drawExtents = drawExtents.Intersect(clipExtents - CurrentState().shadowOffset);
|
||||
|
||||
gfxContext* ctx = blur.Init(drawExtents, blurRadius, nsnull);
|
||||
gfxContext* ctx = blur.Init(drawExtents, blurRadius, nsnull, nsnull);
|
||||
|
||||
if (!ctx)
|
||||
return nsnull;
|
||||
|
@ -235,6 +235,20 @@ struct NS_GFX nsIntRect {
|
||||
height += aMargin.top + aMargin.bottom;
|
||||
}
|
||||
|
||||
// Deflate the rect by the specified width/height or margin
|
||||
void Deflate(PRInt32 aDx, PRInt32 aDy) {
|
||||
x += aDx;
|
||||
y += aDy;
|
||||
width -= aDx*2;
|
||||
height -= aDy*2;
|
||||
}
|
||||
void Deflate(const nsIntMargin &aMargin) {
|
||||
x += aMargin.left;
|
||||
y += aMargin.top;
|
||||
width -= (aMargin.left + aMargin.right);
|
||||
height -= (aMargin.top + aMargin.bottom);
|
||||
}
|
||||
|
||||
// Overloaded operators. Note that '=' isn't defined so we'll get the
|
||||
// compiler generated default assignment operator.
|
||||
PRBool operator==(const nsIntRect& aRect) const {
|
||||
|
@ -52,6 +52,7 @@ GRE_MODULE = 1
|
||||
LIBXUL_LIBRARY = 1
|
||||
|
||||
|
||||
DIRS = utils
|
||||
|
||||
CPPSRCS = \
|
||||
nsThebesDeviceContext.cpp \
|
||||
|
70
gfx/src/thebes/utils/Makefile.in
Normal file
70
gfx/src/thebes/utils/Makefile.in
Normal file
@ -0,0 +1,70 @@
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is thebes gfx
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# mozilla.org.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2010
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Michael Ventnor <m.ventnor@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
# This library can link against both old-gfx and thebes,
|
||||
# and is not a component
|
||||
MODULE = gfx
|
||||
LIBRARY_NAME = gfxutils
|
||||
EXPORT_LIBRARY = 1
|
||||
LIBXUL_LIBRARY = 1
|
||||
|
||||
|
||||
CPPSRCS = \
|
||||
gfxThebesUtils.cpp \
|
||||
gfxBlur.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DSO_LIBS = gkgfx thebes
|
||||
|
||||
EXPORTS += \
|
||||
gfxThebesUtils.h \
|
||||
gfxBlur.h \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DSO_LDOPTS += \
|
||||
$(EXTRA_DSO_LIBS) \
|
||||
$(MOZ_COMPONENT_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
@ -55,7 +55,8 @@ gfxAlphaBoxBlur::~gfxAlphaBoxBlur()
|
||||
gfxContext*
|
||||
gfxAlphaBoxBlur::Init(const gfxRect& aRect,
|
||||
const gfxIntSize& aBlurRadius,
|
||||
const gfxRect* aDirtyRect)
|
||||
const gfxRect* aDirtyRect,
|
||||
const gfxRect* aSkipRect)
|
||||
{
|
||||
mBlurRadius = aBlurRadius;
|
||||
|
||||
@ -80,6 +81,25 @@ gfxAlphaBoxBlur::Init(const gfxRect& aRect,
|
||||
mHasDirtyRect = PR_FALSE;
|
||||
}
|
||||
|
||||
if (aSkipRect) {
|
||||
// If we get passed a skip rect, we can lower the amount of
|
||||
// blurring we need to do. We convert it to nsIntRect to avoid
|
||||
// expensive int<->float conversions if we were to use gfxRect instead.
|
||||
gfxRect skipRect = *aSkipRect;
|
||||
skipRect.RoundIn();
|
||||
mSkipRect = gfxThebesUtils::GfxRectToIntRect(skipRect);
|
||||
nsIntRect shadowIntRect = gfxThebesUtils::GfxRectToIntRect(rect);
|
||||
|
||||
mSkipRect.Deflate(aBlurRadius.width, aBlurRadius.height);
|
||||
mSkipRect.IntersectRect(mSkipRect, shadowIntRect);
|
||||
if (mSkipRect == shadowIntRect)
|
||||
return nsnull;
|
||||
|
||||
mSkipRect -= shadowIntRect.TopLeft();
|
||||
} else {
|
||||
mSkipRect = nsIntRect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// Make an alpha-only surface to draw on. We will play with the data after
|
||||
// everything is drawn to create a blur effect.
|
||||
mImageSurface = new gfxImageSurface(gfxIntSize(static_cast<PRInt32>(rect.Width()), static_cast<PRInt32>(rect.Height())),
|
||||
@ -117,36 +137,68 @@ gfxAlphaBoxBlur::PremultiplyAlpha(gfxFloat alpha)
|
||||
* @param aOutput The output buffer.
|
||||
* @param aLeftLobe The number of pixels to blend on the left.
|
||||
* @param aRightLobe The number of pixels to blend on the right.
|
||||
* @param aStride The stride of the buffers.
|
||||
* @param aWidth The number of columns in the buffers.
|
||||
* @param aRows The number of rows in the buffers.
|
||||
* @param aSkipRect An area to skip blurring in.
|
||||
*/
|
||||
static void
|
||||
BoxBlurHorizontal(unsigned char* aInput,
|
||||
unsigned char* aOutput,
|
||||
PRInt32 aLeftLobe,
|
||||
PRInt32 aRightLobe,
|
||||
PRInt32 aStride,
|
||||
PRInt32 aRows)
|
||||
PRInt32 aWidth,
|
||||
PRInt32 aRows,
|
||||
const nsIntRect& aSkipRect)
|
||||
{
|
||||
PRInt32 boxSize = aLeftLobe + aRightLobe + 1;
|
||||
PRBool skipRectCoversWholeRow = 0 >= aSkipRect.x &&
|
||||
aWidth - 1 <= aSkipRect.XMost();
|
||||
|
||||
for (PRInt32 y = 0; y < aRows; y++) {
|
||||
// Check whether the skip rect intersects this row. If the skip
|
||||
// rect covers the whole surface in this row, we can avoid
|
||||
// this row entirely (and any others along the skip rect).
|
||||
PRBool inSkipRectY = y >= aSkipRect.y &&
|
||||
y < aSkipRect.YMost();
|
||||
if (inSkipRectY && skipRectCoversWholeRow) {
|
||||
y = aSkipRect.YMost() - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
PRInt32 alphaSum = 0;
|
||||
for (PRInt32 i = 0; i < boxSize; i++) {
|
||||
PRInt32 pos = i - aLeftLobe;
|
||||
pos = PR_MAX(pos, 0);
|
||||
pos = PR_MIN(pos, aStride - 1);
|
||||
alphaSum += aInput[aStride * y + pos];
|
||||
pos = NS_MAX(pos, 0);
|
||||
pos = NS_MIN(pos, aWidth - 1);
|
||||
alphaSum += aInput[aWidth * y + pos];
|
||||
}
|
||||
for (PRInt32 x = 0; x < aStride; x++) {
|
||||
for (PRInt32 x = 0; x < aWidth; x++) {
|
||||
// Check whether we are within the skip rect. If so, go
|
||||
// to the next point outside the skip rect.
|
||||
if (inSkipRectY && x >= aSkipRect.x &&
|
||||
x < aSkipRect.XMost()) {
|
||||
x = aSkipRect.XMost();
|
||||
if (x >= aWidth)
|
||||
break;
|
||||
|
||||
// Recalculate the neighbouring alpha values for
|
||||
// our new point on the surface.
|
||||
alphaSum = 0;
|
||||
for (PRInt32 i = 0; i < boxSize; i++) {
|
||||
PRInt32 pos = x + i - aLeftLobe;
|
||||
pos = NS_MAX(pos, 0);
|
||||
pos = NS_MIN(pos, aWidth - 1);
|
||||
alphaSum += aInput[aWidth * y + pos];
|
||||
}
|
||||
}
|
||||
PRInt32 tmp = x - aLeftLobe;
|
||||
PRInt32 last = PR_MAX(tmp, 0);
|
||||
PRInt32 next = PR_MIN(tmp + boxSize, aStride - 1);
|
||||
PRInt32 last = NS_MAX(tmp, 0);
|
||||
PRInt32 next = NS_MIN(tmp + boxSize, aWidth - 1);
|
||||
|
||||
aOutput[aStride * y + x] = alphaSum/boxSize;
|
||||
aOutput[aWidth * y + x] = alphaSum/boxSize;
|
||||
|
||||
alphaSum += aInput[aStride * y + next] -
|
||||
aInput[aStride * y + last];
|
||||
alphaSum += aInput[aWidth * y + next] -
|
||||
aInput[aWidth * y + last];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -160,28 +212,52 @@ BoxBlurVertical(unsigned char* aInput,
|
||||
unsigned char* aOutput,
|
||||
PRInt32 aTopLobe,
|
||||
PRInt32 aBottomLobe,
|
||||
PRInt32 aStride,
|
||||
PRInt32 aRows)
|
||||
PRInt32 aWidth,
|
||||
PRInt32 aRows,
|
||||
const nsIntRect& aSkipRect)
|
||||
{
|
||||
PRInt32 boxSize = aTopLobe + aBottomLobe + 1;
|
||||
PRBool skipRectCoversWholeColumn = 0 >= aSkipRect.y &&
|
||||
aRows - 1 <= aSkipRect.YMost();
|
||||
|
||||
for (PRInt32 x = 0; x < aWidth; x++) {
|
||||
PRBool inSkipRectX = x >= aSkipRect.x &&
|
||||
x < aSkipRect.XMost();
|
||||
if (inSkipRectX && skipRectCoversWholeColumn) {
|
||||
x = aSkipRect.XMost() - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (PRInt32 x = 0; x < aStride; x++) {
|
||||
PRInt32 alphaSum = 0;
|
||||
for (PRInt32 i = 0; i < boxSize; i++) {
|
||||
PRInt32 pos = i - aTopLobe;
|
||||
pos = PR_MAX(pos, 0);
|
||||
pos = PR_MIN(pos, aRows - 1);
|
||||
alphaSum += aInput[aStride * pos + x];
|
||||
pos = NS_MAX(pos, 0);
|
||||
pos = NS_MIN(pos, aRows - 1);
|
||||
alphaSum += aInput[aWidth * pos + x];
|
||||
}
|
||||
for (PRInt32 y = 0; y < aRows; y++) {
|
||||
if (inSkipRectX && y >= aSkipRect.y &&
|
||||
y < aSkipRect.YMost()) {
|
||||
y = aSkipRect.YMost();
|
||||
if (y >= aRows)
|
||||
break;
|
||||
|
||||
alphaSum = 0;
|
||||
for (PRInt32 i = 0; i < boxSize; i++) {
|
||||
PRInt32 pos = y + i - aTopLobe;
|
||||
pos = NS_MAX(pos, 0);
|
||||
pos = NS_MIN(pos, aRows - 1);
|
||||
alphaSum += aInput[aWidth * pos + x];
|
||||
}
|
||||
}
|
||||
PRInt32 tmp = y - aTopLobe;
|
||||
PRInt32 last = PR_MAX(tmp, 0);
|
||||
PRInt32 next = PR_MIN(tmp + boxSize, aRows - 1);
|
||||
PRInt32 last = NS_MAX(tmp, 0);
|
||||
PRInt32 next = NS_MIN(tmp + boxSize, aRows - 1);
|
||||
|
||||
aOutput[aStride * y + x] = alphaSum/boxSize;
|
||||
aOutput[aWidth * y + x] = alphaSum/boxSize;
|
||||
|
||||
alphaSum += aInput[aStride * next + x] -
|
||||
aInput[aStride * last + x];
|
||||
alphaSum += aInput[aWidth * next + x] -
|
||||
aInput[aWidth * last + x];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -249,17 +325,17 @@ gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx, const gfxPoint& offset)
|
||||
if (mBlurRadius.width > 0) {
|
||||
PRInt32 lobes[3][2];
|
||||
ComputeLobes(mBlurRadius.width, lobes);
|
||||
BoxBlurHorizontal(boxData, tmpData, lobes[0][0], lobes[0][1], stride, rows);
|
||||
BoxBlurHorizontal(tmpData, boxData, lobes[1][0], lobes[1][1], stride, rows);
|
||||
BoxBlurHorizontal(boxData, tmpData, lobes[2][0], lobes[2][1], stride, rows);
|
||||
BoxBlurHorizontal(boxData, tmpData, lobes[0][0], lobes[0][1], stride, rows, mSkipRect);
|
||||
BoxBlurHorizontal(tmpData, boxData, lobes[1][0], lobes[1][1], stride, rows, mSkipRect);
|
||||
BoxBlurHorizontal(boxData, tmpData, lobes[2][0], lobes[2][1], stride, rows, mSkipRect);
|
||||
}
|
||||
|
||||
if (mBlurRadius.height > 0) {
|
||||
PRInt32 lobes[3][2];
|
||||
ComputeLobes(mBlurRadius.height, lobes);
|
||||
BoxBlurVertical(tmpData, boxData, lobes[0][0], lobes[0][1], stride, rows);
|
||||
BoxBlurVertical(boxData, tmpData, lobes[1][0], lobes[1][1], stride, rows);
|
||||
BoxBlurVertical(tmpData, boxData, lobes[2][0], lobes[2][1], stride, rows);
|
||||
BoxBlurVertical(tmpData, boxData, lobes[0][0], lobes[0][1], stride, rows, mSkipRect);
|
||||
BoxBlurVertical(boxData, tmpData, lobes[1][0], lobes[1][1], stride, rows, mSkipRect);
|
||||
BoxBlurVertical(tmpData, boxData, lobes[2][0], lobes[2][1], stride, rows, mSkipRect);
|
||||
}
|
||||
}
|
||||
|
@ -40,8 +40,8 @@
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "gfxRect.h"
|
||||
#include "gfxTypes.h"
|
||||
#include "gfxThebesUtils.h"
|
||||
|
||||
/**
|
||||
* Implementation of a box blur approximation of a Gaussian blur.
|
||||
@ -69,10 +69,15 @@ public:
|
||||
*
|
||||
* @param aDirtyRect A pointer to a dirty rect, measured in device units, if available.
|
||||
* This will be used for optimizing the blur operation. It is safe to pass NULL here.
|
||||
*
|
||||
* @param aSkipRect A pointer to a rect, measured in device units, that represents an area
|
||||
* where blurring is unnecessary and shouldn't be done for speed reasons. It is safe to
|
||||
* pass NULL here.
|
||||
*/
|
||||
gfxContext* Init(const gfxRect& aRect,
|
||||
const gfxIntSize& aBlurRadius,
|
||||
const gfxRect* aDirtyRect);
|
||||
const gfxRect* aDirtyRect,
|
||||
const gfxRect* aSkipRect);
|
||||
|
||||
/**
|
||||
* Returns the context that should be drawn to supply the alpha mask to be
|
||||
@ -126,7 +131,13 @@ protected:
|
||||
* mHasDirtyRect is TRUE.
|
||||
*/
|
||||
gfxRect mDirtyRect;
|
||||
PRBool mHasDirtyRect;
|
||||
/**
|
||||
* A rect indicating the area where blurring is unnecessary, and the blur
|
||||
* algorithm should skip over it.
|
||||
*/
|
||||
nsIntRect mSkipRect;
|
||||
|
||||
PRPackedBool mHasDirtyRect;
|
||||
};
|
||||
|
||||
#endif /* GFX_BLUR_H */
|
49
gfx/src/thebes/utils/gfxThebesUtils.cpp
Normal file
49
gfx/src/thebes/utils/gfxThebesUtils.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is gfx thebes code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Michael Ventnor <m.ventnor@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "gfxThebesUtils.h"
|
||||
|
||||
// Converts a gfxRect to an nsIntRect for speed
|
||||
nsIntRect
|
||||
gfxThebesUtils::GfxRectToIntRect(const gfxRect& aIn)
|
||||
{
|
||||
nsIntRect result(PRInt32(aIn.X()), PRInt32(aIn.Y()),
|
||||
PRInt32(aIn.Width()), PRInt32(aIn.Height()));
|
||||
NS_ASSERTION(gfxRect(result.x, result.y, result.width, result.height) == aIn,
|
||||
"The given gfxRect isn't rounded properly!");
|
||||
return result;
|
||||
}
|
53
gfx/src/thebes/utils/gfxThebesUtils.h
Normal file
53
gfx/src/thebes/utils/gfxThebesUtils.h
Normal file
@ -0,0 +1,53 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is gfx thebes code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Michael Ventnor <m.ventnor@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "gfxRect.h"
|
||||
#include "nsRect.h"
|
||||
|
||||
#ifndef GFX_THEBES_UTILS_H
|
||||
#define GFX_THEBES_UTILS_H
|
||||
|
||||
class THEBES_API gfxThebesUtils
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Converts a gfxRect into nsIntRect for speed reasons.
|
||||
*/
|
||||
static nsIntRect GfxRectToIntRect(const gfxRect& aIn);
|
||||
};
|
||||
|
||||
#endif /* GFX_THEBES_UTILS_H */
|
@ -12,7 +12,6 @@ MODULE = thebes
|
||||
EXPORTS = gfx3DMatrix.h \
|
||||
gfxASurface.h \
|
||||
gfxAlphaRecovery.h \
|
||||
gfxBlur.h \
|
||||
gfxColor.h \
|
||||
gfxContext.h \
|
||||
gfxFont.h \
|
||||
|
@ -150,6 +150,10 @@ struct THEBES_API gfxRect {
|
||||
// new |RoundAwayFromZero()| method.
|
||||
void Round();
|
||||
|
||||
// Snap the rectangle edges to integer coordinates, such that the
|
||||
// original rectangle contains the resulting rectangle.
|
||||
void RoundIn();
|
||||
|
||||
// Snap the rectangle edges to integer coordinates, such that the
|
||||
// resulting rectangle contains the original rectangle.
|
||||
void RoundOut();
|
||||
|
@ -15,7 +15,6 @@ EXPORT_LIBRARY = 1
|
||||
CPPSRCS = \
|
||||
gfxASurface.cpp \
|
||||
gfxAlphaRecovery.cpp \
|
||||
gfxBlur.cpp \
|
||||
gfxContext.cpp \
|
||||
gfxImageSurface.cpp \
|
||||
gfxFont.cpp \
|
||||
|
@ -103,6 +103,21 @@ gfxRect::Round()
|
||||
size.height = y1 - y0;
|
||||
}
|
||||
|
||||
void
|
||||
gfxRect::RoundIn()
|
||||
{
|
||||
gfxFloat x0 = NS_ceil(X());
|
||||
gfxFloat y0 = NS_ceil(Y());
|
||||
gfxFloat x1 = NS_floor(XMost());
|
||||
gfxFloat y1 = NS_floor(YMost());
|
||||
|
||||
pos.x = x0;
|
||||
pos.y = y0;
|
||||
|
||||
size.width = x1 - x0;
|
||||
size.height = y1 - y0;
|
||||
}
|
||||
|
||||
void
|
||||
gfxRect::RoundOut()
|
||||
{
|
||||
|
@ -1186,6 +1186,14 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
|
||||
gfxRect frameGfxRect = RectToGfxRect(aFrameArea, twipsPerPixel);
|
||||
frameGfxRect.Round();
|
||||
|
||||
// We don't show anything that intersects with the frame we're blurring on. So tell the
|
||||
// blurrer not to do unnecessary work there.
|
||||
gfxRect skipGfxRect = frameGfxRect;
|
||||
if (hasBorderRadius) {
|
||||
skipGfxRect.Inset(PR_MAX(borderRadii[C_TL].height, borderRadii[C_TR].height), 0,
|
||||
PR_MAX(borderRadii[C_BL].height, borderRadii[C_BR].height), 0);
|
||||
}
|
||||
|
||||
for (PRUint32 i = shadows->Length(); i > 0; --i) {
|
||||
nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
|
||||
if (shadowItem->mInset)
|
||||
@ -1210,7 +1218,8 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
|
||||
nsRefPtr<gfxContext> shadowContext;
|
||||
nsContextBoxBlur blurringArea;
|
||||
|
||||
shadowContext = blurringArea.Init(shadowRect, blurRadius, twipsPerPixel, renderContext, aDirtyRect);
|
||||
shadowContext = blurringArea.Init(shadowRect, blurRadius, twipsPerPixel, renderContext,
|
||||
aDirtyRect, &skipGfxRect);
|
||||
if (!shadowContext)
|
||||
continue;
|
||||
|
||||
@ -1337,46 +1346,9 @@ nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext,
|
||||
shadowClipRect.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
|
||||
shadowClipRect.Deflate(shadowItem->mSpread, shadowItem->mSpread);
|
||||
|
||||
gfxContext* renderContext = aRenderingContext.ThebesContext();
|
||||
nsRefPtr<gfxContext> shadowContext;
|
||||
nsContextBoxBlur blurringArea;
|
||||
|
||||
shadowContext = blurringArea.Init(shadowPaintRect, blurRadius, twipsPerPixel, renderContext, aDirtyRect);
|
||||
if (!shadowContext)
|
||||
continue;
|
||||
|
||||
// Set the shadow color; if not specified, use the foreground color
|
||||
nscolor shadowColor;
|
||||
if (shadowItem->mHasColor)
|
||||
shadowColor = shadowItem->mColor;
|
||||
else
|
||||
shadowColor = aForFrame->GetStyleColor()->mColor;
|
||||
|
||||
renderContext->Save();
|
||||
renderContext->SetColor(gfxRGBA(shadowColor));
|
||||
|
||||
// Clip the context to the area of the frame's padding rect, so no part of the
|
||||
// shadow is painted outside
|
||||
gfxRect shadowGfxRect = RectToGfxRect(paddingRect, twipsPerPixel);
|
||||
shadowGfxRect.Round();
|
||||
renderContext->NewPath();
|
||||
if (hasBorderRadius)
|
||||
renderContext->RoundedRectangle(shadowGfxRect, innerRadii, PR_FALSE);
|
||||
else
|
||||
renderContext->Rectangle(shadowGfxRect);
|
||||
renderContext->Clip();
|
||||
|
||||
// Fill the temporary surface minus the area within the frame that we should
|
||||
// not paint in, and blur and apply it
|
||||
gfxRect shadowPaintGfxRect = RectToGfxRect(shadowPaintRect, twipsPerPixel);
|
||||
gfxRect shadowClipGfxRect = RectToGfxRect(shadowClipRect, twipsPerPixel);
|
||||
shadowPaintGfxRect.RoundOut();
|
||||
shadowClipGfxRect.Round();
|
||||
shadowContext->NewPath();
|
||||
shadowContext->Rectangle(shadowPaintGfxRect);
|
||||
gfxCornerSizes clipRectRadii;
|
||||
if (hasBorderRadius) {
|
||||
// Calculate the radii the inner clipping rect will have
|
||||
gfxCornerSizes clipRectRadii;
|
||||
gfxFloat spreadDistance = shadowItem->mSpread / twipsPerPixel;
|
||||
gfxFloat borderSizes[4] = {0, 0, 0, 0};
|
||||
|
||||
@ -1399,10 +1371,63 @@ nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext,
|
||||
|
||||
nsCSSBorderRenderer::ComputeInnerRadii(innerRadii, borderSizes,
|
||||
&clipRectRadii);
|
||||
shadowContext->RoundedRectangle(shadowClipGfxRect, clipRectRadii, PR_FALSE);
|
||||
} else {
|
||||
shadowContext->Rectangle(shadowClipGfxRect);
|
||||
}
|
||||
|
||||
// Set the "skip rect" to the area within the frame that we don't paint in,
|
||||
// including after blurring. We also use this for clipping later on.
|
||||
nsRect skipRect = shadowClipRect;
|
||||
skipRect.Deflate(blurRadius, blurRadius);
|
||||
gfxRect skipGfxRect = RectToGfxRect(skipRect, twipsPerPixel);
|
||||
if (hasBorderRadius) {
|
||||
skipGfxRect.Inset(PR_MAX(clipRectRadii[C_TL].height, clipRectRadii[C_TR].height), 0,
|
||||
PR_MAX(clipRectRadii[C_BL].height, clipRectRadii[C_BR].height), 0);
|
||||
}
|
||||
|
||||
gfxContext* renderContext = aRenderingContext.ThebesContext();
|
||||
nsRefPtr<gfxContext> shadowContext;
|
||||
nsContextBoxBlur blurringArea;
|
||||
|
||||
shadowContext = blurringArea.Init(shadowPaintRect, blurRadius, twipsPerPixel, renderContext,
|
||||
aDirtyRect, &skipGfxRect);
|
||||
if (!shadowContext)
|
||||
continue;
|
||||
|
||||
// Set the shadow color; if not specified, use the foreground color
|
||||
nscolor shadowColor;
|
||||
if (shadowItem->mHasColor)
|
||||
shadowColor = shadowItem->mColor;
|
||||
else
|
||||
shadowColor = aForFrame->GetStyleColor()->mColor;
|
||||
|
||||
renderContext->Save();
|
||||
renderContext->SetColor(gfxRGBA(shadowColor));
|
||||
|
||||
// Clip the context to the area of the frame's padding rect, so no part of the
|
||||
// shadow is painted outside. Also cut out anything beyond where the inset shadow
|
||||
// will be.
|
||||
gfxRect shadowGfxRect = RectToGfxRect(paddingRect, twipsPerPixel);
|
||||
shadowGfxRect.Round();
|
||||
renderContext->NewPath();
|
||||
if (hasBorderRadius)
|
||||
renderContext->RoundedRectangle(shadowGfxRect, innerRadii, PR_FALSE);
|
||||
else
|
||||
renderContext->Rectangle(shadowGfxRect);
|
||||
renderContext->Rectangle(skipGfxRect);
|
||||
renderContext->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
|
||||
renderContext->Clip();
|
||||
|
||||
// Fill the temporary surface minus the area within the frame that we should
|
||||
// not paint in, and blur and apply it
|
||||
gfxRect shadowPaintGfxRect = RectToGfxRect(shadowPaintRect, twipsPerPixel);
|
||||
shadowPaintGfxRect.RoundOut();
|
||||
gfxRect shadowClipGfxRect = RectToGfxRect(shadowClipRect, twipsPerPixel);
|
||||
shadowClipGfxRect.Round();
|
||||
shadowContext->NewPath();
|
||||
shadowContext->Rectangle(shadowPaintGfxRect);
|
||||
if (hasBorderRadius)
|
||||
shadowContext->RoundedRectangle(shadowClipGfxRect, clipRectRadii, PR_FALSE);
|
||||
else
|
||||
shadowContext->Rectangle(shadowClipGfxRect);
|
||||
shadowContext->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
|
||||
shadowContext->Fill();
|
||||
|
||||
@ -3708,7 +3733,8 @@ gfxContext*
|
||||
nsContextBoxBlur::Init(const nsRect& aRect, nscoord aBlurRadius,
|
||||
PRInt32 aAppUnitsPerDevPixel,
|
||||
gfxContext* aDestinationCtx,
|
||||
const nsRect& aDirtyRect)
|
||||
const nsRect& aDirtyRect,
|
||||
const gfxRect* aSkipRect)
|
||||
{
|
||||
if (aRect.IsEmpty()) {
|
||||
mContext = nsnull;
|
||||
@ -3732,7 +3758,8 @@ nsContextBoxBlur::Init(const nsRect& aRect, nscoord aBlurRadius,
|
||||
dirtyRect.RoundOut();
|
||||
|
||||
// Create the temporary surface for blurring
|
||||
mContext = blur.Init(rect, gfxIntSize(blurRadius, blurRadius), &dirtyRect);
|
||||
mContext = blur.Init(rect, gfxIntSize(blurRadius, blurRadius),
|
||||
&dirtyRect, aSkipRect);
|
||||
return mContext;
|
||||
}
|
||||
|
||||
|
@ -428,6 +428,9 @@ public:
|
||||
* @param aDirtyRect The absolute dirty rect in app units. Used to
|
||||
* optimize the temporary surface size and speed up blur.
|
||||
*
|
||||
* @param aSkipRect An area in device pixels (NOT app units!) to avoid
|
||||
* blurring over, to prevent unnecessary work.
|
||||
*
|
||||
* @return A blank 8-bit alpha-channel-only graphics context to
|
||||
* draw on, or null on error. Must not be freed. The
|
||||
* context has a device offset applied to it given by
|
||||
@ -443,7 +446,7 @@ public:
|
||||
*/
|
||||
gfxContext* Init(const nsRect& aRect, nscoord aBlurRadius,
|
||||
PRInt32 aAppUnitsPerDevPixel, gfxContext* aDestinationCtx,
|
||||
const nsRect& aDirtyRect);
|
||||
const nsRect& aDirtyRect, const gfxRect* aSkipRect);
|
||||
|
||||
/**
|
||||
* Does the actual blurring and mask applying. Users of this object *must*
|
||||
|
@ -59,7 +59,7 @@ GRE_MODULE = 1
|
||||
LIBXUL_LIBRARY = 1
|
||||
|
||||
ifndef MOZ_ENABLE_LIBXUL
|
||||
EXTRA_DSO_LIBS = gkgfx
|
||||
EXTRA_DSO_LIBS = gkgfx gfxutils
|
||||
endif
|
||||
EXTRA_DSO_LIBS += thebes layers
|
||||
|
||||
|
@ -264,7 +264,7 @@ nsDisplayTextShadow::Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsContextBoxBlur contextBoxBlur;
|
||||
gfxContext* shadowCtx = contextBoxBlur.Init(shadowRect, mBlurRadius,
|
||||
presContext->AppUnitsPerDevPixel(),
|
||||
thebesCtx, mVisibleRect);
|
||||
thebesCtx, mVisibleRect, nsnull);
|
||||
if (!shadowCtx)
|
||||
return;
|
||||
|
||||
|
@ -4481,12 +4481,12 @@ nsTextFrame::PaintOneShadow(PRUint32 aOffset, PRUint32 aLength,
|
||||
gfxRect shadowGfxRect = shadowMetrics.mBoundingBox +
|
||||
gfxPoint(aFramePt.x, aTextBaselinePt.y) + shadowOffset;
|
||||
nsRect shadowRect(shadowGfxRect.X(), shadowGfxRect.Y(),
|
||||
shadowGfxRect.Width(), shadowGfxRect.Height());;
|
||||
shadowGfxRect.Width(), shadowGfxRect.Height());
|
||||
|
||||
nsContextBoxBlur contextBoxBlur;
|
||||
gfxContext* shadowContext = contextBoxBlur.Init(shadowRect, blurRadius,
|
||||
PresContext()->AppUnitsPerDevPixel(),
|
||||
aCtx, aDirtyRect);
|
||||
aCtx, aDirtyRect, nsnull);
|
||||
if (!shadowContext)
|
||||
return;
|
||||
|
||||
|
24
layout/reftests/box-shadow/boxshadow-skiprect-ref.html
Normal file
24
layout/reftests/box-shadow/boxshadow-skiprect-ref.html
Normal file
@ -0,0 +1,24 @@
|
||||
<!DOCTYPE HTML>
|
||||
<style>
|
||||
|
||||
#thediv {
|
||||
width: 400px;
|
||||
height: 250px;
|
||||
position: absolute;
|
||||
top: -500px;
|
||||
left: -500px;
|
||||
-moz-box-shadow: 540px 540px 15px black;
|
||||
}
|
||||
|
||||
#blankdiv {
|
||||
width: 400px;
|
||||
height: 250px;
|
||||
background-color: white;
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: 40px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="thediv"> </div>
|
||||
<div id="blankdiv"> </div>
|
14
layout/reftests/box-shadow/boxshadow-skiprect.html
Normal file
14
layout/reftests/box-shadow/boxshadow-skiprect.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!DOCTYPE HTML>
|
||||
<style>
|
||||
|
||||
#thediv {
|
||||
width: 400px;
|
||||
height: 250px;
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: 40px;
|
||||
-moz-box-shadow: 0px 0px 15px black;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="thediv"> </div>
|
@ -13,3 +13,4 @@
|
||||
== boxshadow-rounded-spread.html boxshadow-rounded-spread-ref.html
|
||||
HTTP(..) == boxshadow-dynamic.xul boxshadow-dynamic-ref.xul
|
||||
== boxshadow-onecorner.html boxshadow-onecorner-ref.html
|
||||
== boxshadow-skiprect.html boxshadow-skiprect-ref.html
|
||||
|
@ -579,7 +579,7 @@ void nsTextBoxFrame::PaintOneShadow(gfxContext* aCtx,
|
||||
nsContextBoxBlur contextBoxBlur;
|
||||
gfxContext* shadowContext = contextBoxBlur.Init(shadowRect, blurRadius,
|
||||
PresContext()->AppUnitsPerDevPixel(),
|
||||
aCtx, aDirtyRect);
|
||||
aCtx, aDirtyRect, nsnull);
|
||||
|
||||
if (!shadowContext)
|
||||
return;
|
||||
|
@ -115,6 +115,7 @@ STATIC_LIBS += \
|
||||
xpcom_core \
|
||||
ucvutil_s \
|
||||
gkgfx \
|
||||
gfxutils \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_IPC
|
||||
|
Loading…
Reference in New Issue
Block a user