Implement background-image: -moz-image-rect(), which allows a region of an image to be used as a background image. (Bug 113577) r=roc, dbaron

This commit is contained in:
Ryo Kawaguchi 2009-08-21 13:39:25 -07:00
Родитель 47149e6feb
Коммит f6adb8114c
43 изменённых файлов: 1917 добавлений и 317 удалений

Просмотреть файл

@ -81,6 +81,52 @@
#include "nsCSSRenderingBorders.h"
/**
* This is a small wrapper class to encapsulate image drawing that can draw an
* nsStyleImage image, which may internally be a real image, a sub image, or a
* CSS gradient.
*
* @note Always call the member functions in the order of PrepareImage(),
* ComputeSize(), and Draw().
*/
class ImageRenderer {
public:
ImageRenderer(nsIFrame* aForFrame, const nsStyleImage& aImage);
~ImageRenderer();
/**
* Populates member variables to get ready for rendering.
* @return PR_TRUE iff the image is ready, and there is at least a pixel to
* draw.
*/
PRBool PrepareImage();
/**
* @return the image size in appunits. CSS gradient images don't have an
* intrinsic size so we have to pass in a default that they will use.
*/
nsSize ComputeSize(const nsSize& aDefault);
/**
* Draws the image to the target rendering context.
* @param aRepeat indicates whether the image is to be repeated (tiled)
* @see nsLayoutUtils::DrawImage() for other parameters
*/
void Draw(nsPresContext* aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDest,
const nsRect& aFill,
const nsPoint& aAnchor,
const nsRect& aDirty,
PRBool aRepeat);
private:
nsIFrame* mForFrame;
nsStyleImage mImage;
nsStyleImageType mType;
nsCOMPtr<imgIContainer> mImageContainer;
nsRefPtr<nsStyleGradient> mGradientData;
PRBool mIsReady;
nsSize mSize;
};
// To avoid storing this data on nsInlineFrame (bloat) and to avoid
// recalculating this for each frame in a continuation (perf), hold
// a cache of various coordinate information that we need in order
@ -1396,23 +1442,6 @@ IsSolidBorder(const nsStyleBorder& aBorder)
return PR_TRUE;
}
/**
* Returns true if the given request is for a background image (that is, it is
* non-null) and that image is fully loaded and its size calculated.
*/
static PRBool
HaveCompleteBackgroundImage(imgIRequest *aRequest)
{
if (!aRequest)
return PR_FALSE;
PRUint32 status = imgIRequest::STATUS_ERROR;
aRequest->GetImageStatus(&status);
return (status & imgIRequest::STATUS_FRAME_COMPLETE) &&
(status & imgIRequest::STATUS_SIZE_AVAILABLE);
}
static inline void
SetupDirtyRects(const nsRect& aBGClipArea, const nsRect& aCallerDirtyRect,
nscoord aAppUnitsPerPixel,
@ -1502,8 +1531,7 @@ DetermineBackgroundColorInternal(nsPresContext* aPresContext,
const nsStyleBackground& aBackground,
nsIFrame* aFrame,
PRBool& aDrawBackgroundImage,
PRBool& aDrawBackgroundColor,
nsCOMPtr<imgIRequest>& aBottomImage)
PRBool& aDrawBackgroundColor)
{
aDrawBackgroundImage = PR_TRUE;
aDrawBackgroundColor = PR_TRUE;
@ -1513,15 +1541,6 @@ DetermineBackgroundColorInternal(nsPresContext* aPresContext,
aDrawBackgroundColor = aPresContext->GetBackgroundColorDraw();
}
if (aBackground.BottomLayer().mImage.GetType() == eBackgroundImage_Image) {
aBottomImage = aBackground.BottomLayer().mImage.GetImageData();
if (!aDrawBackgroundImage || !HaveCompleteBackgroundImage(aBottomImage)) {
aBottomImage = nsnull;
}
} else {
aBottomImage = nsnull;
}
nscolor bgColor;
if (aDrawBackgroundColor) {
bgColor = aBackground.mBackgroundColor;
@ -1549,13 +1568,11 @@ nsCSSRendering::DetermineBackgroundColor(nsPresContext* aPresContext,
{
PRBool drawBackgroundImage;
PRBool drawBackgroundColor;
nsCOMPtr<imgIRequest> bottomImage;
return DetermineBackgroundColorInternal(aPresContext,
aBackground,
aFrame,
drawBackgroundImage,
drawBackgroundColor,
bottomImage);
drawBackgroundColor);
}
static gfxFloat
@ -1677,14 +1694,11 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
PRBool drawBackgroundImage;
PRBool drawBackgroundColor;
nsCOMPtr<imgIRequest> bottomImage;
nscolor bgColor = DetermineBackgroundColorInternal(aPresContext,
aBackground,
aForFrame,
drawBackgroundImage,
drawBackgroundColor,
bottomImage);
drawBackgroundColor);
// At this point, drawBackgroundImage and drawBackgroundColor are
// true if and only if we are actually supposed to paint an image or
@ -1765,15 +1779,11 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
// association of the style data with the frame.
aPresContext->SetupBackgroundImageLoaders(aForFrame, &aBackground);
if (bottomImage &&
// We can skip painting the background color if a background image is opaque.
if (drawBackgroundColor &&
aBackground.BottomLayer().mRepeat == NS_STYLE_BG_REPEAT_XY &&
drawBackgroundColor) {
nsCOMPtr<imgIContainer> image;
bottomImage->GetImage(getter_AddRefs(image));
PRBool isOpaque;
if (NS_SUCCEEDED(image->GetCurrentFrameIsOpaque(&isOpaque)) && isOpaque)
drawBackgroundColor = PR_FALSE;
}
aBackground.BottomLayer().mImage.IsOpaque())
drawBackgroundColor = PR_FALSE;
// The background color is rendered over the entire dirty area,
// even if the image isn't.
@ -1892,7 +1902,14 @@ PaintBackgroundLayer(nsPresContext* aPresContext,
* background-repeat
*/
// relative to aBorderArea
ImageRenderer imageRenderer(aForFrame, aLayer.mImage);
if (!imageRenderer.PrepareImage()) {
// There's no image or it's not ready to be painted.
return;
}
// Compute background origin area relative to aBorderArea now as we may need
// it to compute the effective image size for a CSS gradient.
nsRect bgPositioningArea(0, 0, 0, 0);
nsIAtom* frameType = aForFrame->GetType();
@ -1946,30 +1963,8 @@ PaintBackgroundLayer(nsPresContext* aPresContext,
}
}
nsSize imageSize;
nsCOMPtr<imgIContainer> image;
if (aLayer.mImage.GetType() == eBackgroundImage_Image) {
// Lookup the image
imgIRequest *req = aLayer.mImage.GetImageData();
if (!HaveCompleteBackgroundImage(req))
return;
req->GetImage(getter_AddRefs(image));
req = nsnull;
nsIntSize imageIntSize;
image->GetWidth(&imageIntSize.width);
image->GetHeight(&imageIntSize.height);
imageSize.width = nsPresContext::CSSPixelsToAppUnits(imageIntSize.width);
imageSize.height = nsPresContext::CSSPixelsToAppUnits(imageIntSize.height);
} else if (aLayer.mImage.GetType() == eBackgroundImage_Gradient) {
imageSize = bgPositioningArea.Size();
} else {
return;
}
if (imageSize.width == 0 || imageSize.height == 0)
nsSize imageSize = imageRenderer.ComputeSize(bgPositioningArea.Size());
if (imageSize.width <= 0 || imageSize.height <= 0)
return;
// Compute the anchor point.
@ -2077,16 +2072,9 @@ PaintBackgroundLayer(nsPresContext* aPresContext,
}
fillArea.IntersectRect(fillArea, aBGClipRect);
if (aLayer.mImage.GetType() == eBackgroundImage_Image) {
nsLayoutUtils::DrawImage(&aRenderingContext, image,
nsLayoutUtils::GetGraphicsFilterForFrame(aForFrame),
destArea, fillArea, anchor + aBorderArea.TopLeft(), aDirtyRect);
} else {
nsCSSRendering::PaintGradient(aPresContext, aRenderingContext,
aLayer.mImage.GetGradientData(),
aDirtyRect, destArea, fillArea,
(repeat != NS_STYLE_BG_REPEAT_OFF));
}
imageRenderer.Draw(aPresContext, aRenderingContext, destArea, fillArea,
anchor + aBorderArea.TopLeft(), aDirtyRect,
(repeat != NS_STYLE_BG_REPEAT_OFF));
}
static void
@ -3075,6 +3063,145 @@ nsCSSRendering::GetTextDecorationRectInternal(const gfxPoint& aPt,
return r;
}
// ------------------
// ImageRenderer
// ------------------
ImageRenderer::ImageRenderer(nsIFrame* aForFrame,
const nsStyleImage& aImage)
: mForFrame(aForFrame)
, mImage(aImage)
, mType(aImage.GetType())
, mImageContainer(nsnull)
, mGradientData(nsnull)
, mIsReady(PR_FALSE)
, mSize(0, 0)
{
}
ImageRenderer::~ImageRenderer()
{
}
PRBool
ImageRenderer::PrepareImage()
{
if (mImage.IsEmpty() || !mImage.IsComplete()) {
// We can not prepare the image for rendering if it is not fully loaded.
return PR_FALSE;
}
switch (mType) {
case eStyleImageType_Image:
{
nsCOMPtr<imgIContainer> srcImage;
mImage.GetImageData()->GetImage(getter_AddRefs(srcImage));
NS_ABORT_IF_FALSE(srcImage, "If srcImage is null, mImage.IsComplete() "
"should have returned false");
if (!mImage.GetCropRect()) {
mImageContainer.swap(srcImage);
} else {
nsIntRect actualCropRect;
PRBool isEntireImage;
PRBool success =
mImage.ComputeActualCropRect(actualCropRect, &isEntireImage);
NS_ASSERTION(success, "ComputeActualCropRect() should not fail here");
if (!success || actualCropRect.IsEmpty()) {
// The cropped image has zero size
return PR_FALSE;
}
if (isEntireImage) {
// The cropped image is identical to the source image
mImageContainer.swap(srcImage);
} else {
nsCOMPtr<imgIContainer> subImage;
nsresult rv = srcImage->ExtractCurrentFrame(actualCropRect,
getter_AddRefs(subImage));
if (NS_FAILED(rv)) {
NS_WARNING("The cropped image contains no pixels to draw; "
"maybe the crop rect is outside the image frame rect");
return PR_FALSE;
}
mImageContainer.swap(subImage);
}
}
mIsReady = PR_TRUE;
break;
}
case eStyleImageType_Gradient:
mGradientData = mImage.GetGradientData();
mIsReady = PR_TRUE;
break;
case eStyleImageType_Null:
default:
break;
}
return mIsReady;
}
nsSize
ImageRenderer::ComputeSize(const nsSize& aDefault)
{
NS_ASSERTION(mIsReady, "Ensure PrepareImage() has returned true "
"before calling me");
switch (mType) {
case eStyleImageType_Image:
{
nsIntSize imageIntSize;
mImageContainer->GetWidth(&imageIntSize.width);
mImageContainer->GetHeight(&imageIntSize.height);
mSize.width = nsPresContext::CSSPixelsToAppUnits(imageIntSize.width);
mSize.height = nsPresContext::CSSPixelsToAppUnits(imageIntSize.height);
break;
}
case eStyleImageType_Gradient:
mSize = aDefault;
break;
case eStyleImageType_Null:
default:
mSize.SizeTo(0, 0);
break;
}
return mSize;
}
void
ImageRenderer::Draw(nsPresContext* aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDest,
const nsRect& aFill,
const nsPoint& aAnchor,
const nsRect& aDirty,
PRBool aRepeat)
{
if (!mIsReady) {
NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
return;
}
if (aDest.IsEmpty() || aFill.IsEmpty())
return;
switch (mType) {
case eStyleImageType_Image:
nsLayoutUtils::DrawImage(&aRenderingContext, mImageContainer,
nsLayoutUtils::GetGraphicsFilterForFrame(mForFrame),
aDest, aFill, aAnchor, aDirty);
break;
case eStyleImageType_Gradient:
nsCSSRendering::PaintGradient(aPresContext, aRenderingContext,
mGradientData, aDirty, aDest, aFill, aRepeat);
break;
case eStyleImageType_Null:
default:
break;
}
}
// -----
// nsContextBoxBlur
// -----

Просмотреть файл

@ -607,23 +607,8 @@ nsDisplayBackground::IsOpaque(nsDisplayListBuilder* aBuilder) {
!nsCSSRendering::IsCanvasFrame(mFrame))
return PR_TRUE;
if (bottomLayer.mRepeat == NS_STYLE_BG_REPEAT_XY) {
if (bottomLayer.mImage.GetType() == eBackgroundImage_Image) {
nsCOMPtr<imgIContainer> container;
bottomLayer.mImage.GetImageData()->GetImage(getter_AddRefs(container));
if (container) {
PRBool animated;
container->GetAnimated(&animated);
if (!animated) {
PRBool isOpaque;
if (NS_SUCCEEDED(container->GetCurrentFrameIsOpaque(&isOpaque)))
return isOpaque;
}
}
}
}
return PR_FALSE;
return bottomLayer.mRepeat == NS_STYLE_BG_REPEAT_XY &&
bottomLayer.mImage.IsOpaque();
}
PRBool
@ -637,7 +622,7 @@ nsDisplayBackground::IsUniform(nsDisplayListBuilder* aBuilder) {
nsCSSRendering::FindBackground(mFrame->PresContext(), mFrame, &bg);
if (!hasBG)
return PR_TRUE;
if (bg->BottomLayer().mImage.GetType() == eBackgroundImage_Null &&
if (bg->BottomLayer().mImage.IsEmpty() &&
bg->mImageCount == 1 &&
!nsLayoutUtils::HasNonZeroCorner(mFrame->GetStyleBorder()->mBorderRadius) &&
bg->BottomLayer().mClip == NS_STYLE_BG_CLIP_BORDER)

Просмотреть файл

@ -1268,7 +1268,7 @@ nsPresContext::SetupBackgroundImageLoaders(nsIFrame* aFrame,
{
nsRefPtr<nsImageLoader> loaders;
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, aStyleBackground) {
if (aStyleBackground->mLayers[i].mImage.GetType() == eBackgroundImage_Image) {
if (aStyleBackground->mLayers[i].mImage.GetType() == eStyleImageType_Image) {
imgIRequest *image = aStyleBackground->mLayers[i].mImage.GetImageData();
loaders = nsImageLoader::Create(aFrame, image, PR_FALSE, loaders);
}

Просмотреть файл

@ -4025,7 +4025,7 @@ nsIFrame::CheckInvalidateSizeChange(const nsRect& aOldRect,
const nsStyleBackground *bg = GetStyleBackground();
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
const nsStyleBackground::Layer &layer = bg->mLayers[i];
if (layer.mImage.GetType() != eBackgroundImage_Null &&
if (!layer.mImage.IsEmpty() &&
(layer.mPosition.mXIsPercent || layer.mPosition.mYIsPercent)) {
Invalidate(nsRect(0, 0, aOldRect.width, aOldRect.height));
return;

Просмотреть файл

@ -0,0 +1,50 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
test1 and test2 test -moz-image-rect() where the image rect is specified by
mixed pixel values and percentage values.
-moz-image-rect() can also take a floating point value for each side, and
each floating point value (after percent to pixel conversion) is rounded to
the nearest integer. test3 and test4 test if the rounding operation is
working as expected.
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
width: 32px;
height: 32px;
background: no-repeat;
}
#test1 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0, 32, 100%, 0%);
}
#test2 {
background-image: -moz-image-rect(url(transparent-16x16-in-blue-32x32.png), 0%, 32, 50%, 0);
}
#test3 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0.3, 16.2, 15.5, 0.4);
}
#test4 {
background-color: yellow;
background-image: -moz-image-rect(url(transparent-16x16-in-blue-32x32.png), 51.2%, 100.4%, 99.2%, 48.9%);
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
<div class="wrapper"><div id="test3"></div></div>
<div class="wrapper"><div id="test4"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,45 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
Tests some common usages of -moz-image-rect() with image rect specified by
percentage values.
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
width: 32px;
height: 32px;
background: no-repeat;
}
#test1 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0%, 100%, 100%, 0%);
}
#test2 {
background-image: -moz-image-rect(url(transparent-16x16-in-blue-32x32.png), 0%, 100%, 50%, 0%);
}
#test3 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0%, 50%, 50%, 0%);
}
#test4 {
background-color: yellow;
background-image: -moz-image-rect(url(transparent-16x16-in-blue-32x32.png), 50%, 100%, 100%, 50%);
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
<div class="wrapper"><div id="test3"></div></div>
<div class="wrapper"><div id="test4"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,45 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
Tests some common usages of -moz-image-rect() with image rect specified by
pixel values.
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
width: 32px;
height: 32px;
background: no-repeat;
}
#test1 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0, 32, 32, 0);
}
#test2 {
background-image: -moz-image-rect(url(transparent-16x16-in-blue-32x32.png), 0, 32, 16, 0);
}
#test3 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0, 16, 16, 0);
}
#test4 {
background-color: yellow;
background-image: -moz-image-rect(url(transparent-16x16-in-blue-32x32.png), 16, 32, 32, 16);
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
<div class="wrapper"><div id="test3"></div></div>
<div class="wrapper"><div id="test4"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,52 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
background-repeat: no-repeat;
}
#test1 {
width: 32px;
height: 32px;
background-position: 0px 0px;
background-image: url('green-16x16-in-blue-32x32.png');
}
#test2 {
width: 32px;
height: 16px;
background-position: 0px 0px;
background-image: url('transparent-16x16-in-blue-32x32.png');
}
#test3 {
width: 16px;
height: 16px;
background-position: 0px 0px;
background-image: url('green-16x16-in-blue-32x32.png');
}
#test4 {
width: 32px;
height: 32px;
background-color: yellow;
background-position: -16px -16px;
background-image: url('transparent-16x16-in-blue-32x32.png');
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
<div class="wrapper"><div id="test3"></div></div>
<div class="wrapper"><div id="test4"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,50 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
Makes sure that no image is drawn when an empty region of the source image
is specified by -moz-image-rect().
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
width: 32px;
height: 32px;
background: no-repeat;
}
/* Zero width and height */
#test1 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0, 0, 0, 0);
}
/* Negative height */
#test2 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 32, 32, 0, 0);
}
/* Image rect outside the source image */
#test3 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 100, 200, 200, 100);
}
/* Negative height */
#test4 {
/* It is only after the source image size is available that it can be
determined if this image is empty or not. */
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 16, 32, 50%, 16);
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
<div class="wrapper"><div id="test3"></div></div>
<div class="wrapper"><div id="test4"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,48 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
Tests if the CSS parser can detect wrong syntax of -moz-image-rect() and
gracefully fail.
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
width: 32px;
height: 32px;
background: no-repeat;
}
#test1 {
/* only non-negative values accepted */
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), -1, 16, 16, 0);
}
#test2 {
/* only bare numbers and percent values accepted */
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0px, 16, 16, 0);
}
#test3 {
/* must have a complete set of <top>, <right>, <bottom>, <left> */
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 16, 16);
}
#test4 {
/* must be comma separated */
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png) 0, 16, 16, 0);
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
<div class="wrapper"><div id="test3"></div></div>
<div class="wrapper"><div id="test4"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,43 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
Tests if some unusual source images do not cause a crash.
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
width: 32px;
height: 32px;
background: no-repeat;
}
#test1 {
background-image: -moz-image-rect(url(missing.png), 0, 16, 16, 0);
}
#test2 {
background-image: -moz-image-rect(url(#), 0, 16, 16, 0);
}
#test3 {
background-image: -moz-image-rect(url(../backgrounds/malformed.png), 0, 16, 16, 0);
}
#test4 {
background-image: -moz-image-rect(url(../backgrounds/transparent-32x32.png), 0, 16, 16, 0);
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
<div class="wrapper"><div id="test3"></div></div>
<div class="wrapper"><div id="test4"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,24 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
<div class="wrapper"><div id="test3"></div></div>
<div class="wrapper"><div id="test4"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,29 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
width: 32px;
height: 32px;
background: url(green-16x16-in-blue-32x32.png) no-repeat;
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
<div class="wrapper"><div id="test3"></div></div>
<div class="wrapper"><div id="test4"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,47 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
Checks if huge values that overflow when converted to PRInt32 and small
non-zero values do not cause a crash or an unexpected behavior.
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
width: 32px;
height: 32px;
}
/* Huge values that exceed PR_INT32_MAX are clamped to PR_INT32_MAX, so
all the tests below should display the entire 32x32 image. */
#test1 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0, 10000000000, 32, 0);
}
#test2 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0%, 10000000000%, 100%, 0%);
}
/* Small values (smaller than machine epsilon) are rounded to zero, so
all the tests below should display the entire 32x32 image. */
#test3 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0.00000000001, 32, 32, 0);
}
#test4 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0.00000000001%, 100%, 100%, 0%);
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
<div class="wrapper"><div id="test3"></div></div>
<div class="wrapper"><div id="test4"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,27 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
width: 16px;
height: 16px;
background: -16px -16px url('green-16x16-in-blue-32x32.png') no-repeat;
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,38 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
Tests image rects that run off the source image bounds.
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
width: 32px;
height: 32px;
background: no-repeat;
}
/* The final crop rect is computed by intersecting an image rect and the
source image bounds, so the following tests should display the bottom
right 16x16 corner of the image. */
#test1 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 16, 50, 50, 16);
}
#test2 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 50.000001%, 1000000%, 1000000%, 50.000001%);
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,40 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
}
#test1, #test2, #test3 {
width: 16px;
height: 16px;
background: url('green-16x16-in-blue-32x32.png') no-repeat;
}
#test4 {
width: 32px;
height: 32px;
background-color: yellow;
}
#test5, #test6 {
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
<div class="wrapper"><div id="test3"></div></div>
<div class="wrapper"><div id="test4"></div></div>
<div class="wrapper"><div id="test5"></div></div>
<div class="wrapper"><div id="test6"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,64 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
Checks if the CSS parser can parse variations of -moz-image-rect() syntax
correctly or fail gracefully.
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
width: 32px;
height: 32px;
background: no-repeat;
}
#test1 {
/* tests shorthand notation */
background: transparent scroll no-repeat 0px 0px -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0, 16, 16, 0);
}
#test2 {
/* URL can be a quoted string */
background-image: -moz-image-rect('green-16x16-in-blue-32x32.png',0,16,16,0);
}
#test3 {
/* URL can be a quoted string */
background-image: -moz-image-rect( "green-16x16-in-blue-32x32.png" , 0 , 16 , 16 , 0 );
}
#test4 {
/* Non-quoted URL is not allowed. When the parser encounters a syntax
error, it skips until the closing parenthesis, so background-color
should be painted with yellow since -moz-image-rect(...) is ignored. */
background-image: -moz-image-rect(green-16x16-in-blue-32x32.png, 0, 16, 16, 0);
background-color: yellow;
}
#test5 {
/* Non-quoted URL is not allowed. When the parser encounters a syntax
error, it skips until the closing parenthesis, so background-color
should be ignored since there is no matching closing parenthesis. */
background-image: -moz-image-rect(green-16x16-in-blue-32x32.png, 0, 16, 16, 0;
background-color: yellow;
}
#test6 {
/* this is ignored due to the missing closing parenthesis in #test5 */
background-color: yellow;
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
<div class="wrapper"><div id="test3"></div></div>
<div class="wrapper"><div id="test4"></div></div>
<div class="wrapper"><div id="test5"></div></div>
<div class="wrapper"><div id="test6"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,50 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
#test1 {
width: 32px;
height: 32px;
background-color: #00ff00;
}
#test2 {
width: 16px;
height: 16px;
background-color: #00ff00;
}
#test3 {
width: 32px;
height: 16px;
background-image: url('green-16x16-in-blue-32x32.png');
}
#test4 {
width: 16px;
height: 16px;
background-color: #00ff00;
}
#test5 {
width: 32px;
height: 32px;
background-color: #00ff00;
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
<div class="wrapper"><div id="test3"></div></div>
<div class="wrapper"><div id="test4"></div></div>
<div class="wrapper"><div id="test5"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,56 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
Tests if -moz-image-rect() works collaboratively with other background
properties as expected.
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
width: 32px;
height: 32px;
}
/* tests with background-repeat */
#test1 {
background: repeat -moz-image-rect(url(green-16x16-in-blue-32x32.png), 8, 24, 24, 8);
}
/* tests with background-position */
#test2 {
background: no-repeat -8px -8px -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0, 24, 24, 0);
}
/* tests with background layers */
#test3 {
background: no-repeat 0px 0px -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0, 16, 16, 0),
no-repeat 16px 0px -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0, 32, 16, 16);
}
/* for comparison with test5 */
#test4 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 8, 24, 24, 8);
background-repeat: no-repeat;
}
/* tests with background-size */
#test5 {
-moz-background-size: 100% 100%;
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 8, 24, 24, 8);
background-repeat: no-repeat;
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
<div class="wrapper"><div id="test3"></div></div>
<div class="wrapper"><div id="test4"></div></div>
<div class="wrapper"><div id="test5"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,55 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
This file is identical to background-common-usage-ref.html except the
zoom factor.
-->
<html reftest-zoom="1.3">
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
background-repeat: no-repeat;
}
#test1 {
width: 32px;
height: 32px;
background-position: 0px 0px;
background-image: url('green-16x16-in-blue-32x32.png');
}
#test2 {
width: 32px;
height: 16px;
background-position: 0px 0px;
background-image: url('transparent-16x16-in-blue-32x32.png');
}
#test3 {
width: 16px;
height: 16px;
background-position: 0px 0px;
background-image: url('green-16x16-in-blue-32x32.png');
}
#test4 {
width: 32px;
height: 32px;
background-color: yellow;
background-position: -16px -16px;
background-image: url('transparent-16x16-in-blue-32x32.png');
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
<div class="wrapper"><div id="test3"></div></div>
<div class="wrapper"><div id="test4"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,49 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
Checks if the full zoom (x1.3) on -moz-image-rect() produces the same
result as the same full zoom on the CSS sprites produced by hacking
background-position.
This file is identical to background-common-usage-pixel.html except the
zoom factor.
-->
<html reftest-zoom="1.3">
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
width: 32px;
height: 32px;
background: no-repeat;
}
#test1 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0, 32, 32, 0);
}
#test2 {
background-image: -moz-image-rect(url(transparent-16x16-in-blue-32x32.png), 0, 32, 16, 0);
}
#test3 {
background-image: -moz-image-rect(url(green-16x16-in-blue-32x32.png), 0, 16, 16, 0);
}
#test4 {
background-color: yellow;
background-image: -moz-image-rect(url(transparent-16x16-in-blue-32x32.png), 16, 32, 32, 16);
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<div class="wrapper"><div id="test2"></div></div>
<div class="wrapper"><div id="test3"></div></div>
<div class="wrapper"><div id="test4"></div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,66 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
Tests if getComputedStyle() works on -moz-image-rect() and formats the
output correctly.
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
width: 32px;
height: 32px;
background: no-repeat;
}
</style>
<script>
var curdir = location.href.replace(/[^/]+$/, "");
// Tests a common usage
var test1 = "-moz-image-rect(url(green-16x16-in-blue-32x32.png), 0, 16, 16, 0)";
var testRef1 = "-moz-image-rect(url(\"" + curdir + "green-16x16-in-blue-32x32.png\"), 0, 16, 16, 0)";
// Tests an irregular but valid usage
var test2 = "-moz-image-rect( 'green-16x16-in-blue-32x32.png' , 0.0% , 50.5% , 49.5% , 0.0% )";
var testRef2 = "-moz-image-rect(url(\"" + curdir + "green-16x16-in-blue-32x32.png\"), 0%, 50.5%, 49.5%, 0%)";
// Tests a wrong syntax (negative value)
var test3 = "-moz-image-rect(url(green-16x16-in-blue-32x32.png), 0%, -50%, 50%, 0%)";
var testRef3 = "none";
// Checks if I didn't break the default url() notation.
var test4 = "url( green-16x16-in-blue-32x32.png )";
var testRef4 = "url(\"" + curdir + "green-16x16-in-blue-32x32.png\")";
function equalComputedDOMIO(domInput, domOutputRef, targetId) {
var targetObj = document.getElementById(targetId);
targetObj.style.backgroundImage = domInput;
var domOutput = getComputedStyle(targetObj, null).getPropertyValue("background-image");
document.write(domOutput == domOutputRef ? "SUCCESS" : ("FAIL: " + domOutput));
}
</script>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<script>
equalComputedDOMIO(test1, testRef1, "test1");
</script>
<div class="wrapper"><div id="test2"></div></div>
<script>
equalComputedDOMIO(test2, testRef2, "test2");
</script>
<div class="wrapper"><div id="test3"></div></div>
<script>
equalComputedDOMIO(test3, testRef3, "test3");
</script>
<div class="wrapper"><div id="test4"></div></div>
<script>
equalComputedDOMIO(test4, testRef4, "test4");
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,45 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
#test1 {
width: 16px;
height: 16px;
background-image: url('green-16x16-in-blue-32x32.png');
}
#test2 {
width: 16px;
height: 16px;
background-image: url('green-16x16-in-blue-32x32.png');
}
#test3 {
}
#test4 {
width: 32px;
height: 32px;
background-image: url('green-16x16-in-blue-32x32.png');
}
</style>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
SUCCESS
<div class="wrapper"><div id="test2"></div></div>
SUCCESS
<div class="wrapper"><div id="test3"></div></div>
SUCCESS
<div class="wrapper"><div id="test4"></div></div>
SUCCESS
</body>
</html>

Просмотреть файл

@ -0,0 +1,65 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
Tests if the DOM interface of -moz-image-rect() works and formats the
output correctly.
-->
<html>
<head>
<title>Testcases: -moz-image-rect() [bug 113577]</title>
<style>
div.wrapper {
width: 32px;
height: 32px;
margin: 10px;
background-color: red;
}
div.wrapper div {
width: 32px;
height: 32px;
background: no-repeat;
}
</style>
<script>
// Tests a common usage
var test1 = "-moz-image-rect(url(green-16x16-in-blue-32x32.png), 0, 16, 16, 0)";
var testRef1 = "-moz-image-rect(url(\"green-16x16-in-blue-32x32.png\"), 0, 16, 16, 0)";
// Tests an irregular but valid usage
var test2 = "-moz-image-rect( 'green-16x16-in-blue-32x32.png' , 0.0% , 50.5% , 49.5% , 0.0% )";
var testRef2 = "-moz-image-rect(url(\"green-16x16-in-blue-32x32.png\"), 0%, 50.5%, 49.5%, 0%)";
// Tests a wrong syntax (negative value)
var test3 = "-moz-image-rect(url(green-16x16-in-blue-32x32.png), 0%, -50%, 50%, 0%)";
var testRef3 = "";
// Checks if I didn't break the default url() notation.
var test4 = "url( green-16x16-in-blue-32x32.png )";
var testRef4 = "url(\"green-16x16-in-blue-32x32.png\")";
function equalDOMIO(domInput, domOutputRef, targetId) {
var targetObj = document.getElementById(targetId);
targetObj.style.backgroundImage = domInput;
var domOutput = targetObj.style.backgroundImage;
document.write(domOutput == domOutputRef ? "SUCCESS" : ("FAIL: " + domOutput));
}
</script>
</head>
<body>
<div class="wrapper"><div id="test1"></div></div>
<script>
equalDOMIO(test1, testRef1, "test1");
</script>
<div class="wrapper"><div id="test2"></div></div>
<script>
equalDOMIO(test2, testRef2, "test2");
</script>
<div class="wrapper"><div id="test3"></div></div>
<script>
equalDOMIO(test3, testRef3, "test3");
</script>
<div class="wrapper"><div id="test4"></div></div>
<script>
equalDOMIO(test4, testRef4, "test4");
</script>
</body>
</html>

Двоичные данные
layout/reftests/image-rect/green-16x16-in-blue-32x32.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.8 KiB

Просмотреть файл

@ -0,0 +1,13 @@
== background-common-usage-floating-point.html background-common-usage-ref.html
== background-common-usage-percent.html background-common-usage-ref.html
== background-common-usage-pixel.html background-common-usage-ref.html
== background-draw-nothing-empty-rect.html background-draw-nothing-ref.html
== background-draw-nothing-invalid-syntax.html background-draw-nothing-ref.html
== background-draw-nothing-malformed-images.html background-draw-nothing-ref.html
== background-monster-rect.html background-monster-rect-ref.html
== background-over-size-rect.html background-over-size-rect-ref.html
== background-test-parser.html background-test-parser-ref.html
== background-with-other-properties.html background-with-other-properties-ref.html
== background-zoom.html background-zoom-ref.html
== dom-api-computed-style.html dom-api-ref.html
== dom-api.html dom-api-ref.html

Двоичные данные
layout/reftests/image-rect/transparent-16x16-in-blue-32x32.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.8 KiB

Просмотреть файл

@ -89,6 +89,9 @@ include ib-split/reftest.list
# image/
include image/reftest.list
# image-rect/
include image-rect/reftest.list
# image-region/
include image-region/reftest.list

Просмотреть файл

@ -170,6 +170,26 @@ ShouldIgnoreColors(nsRuleData *aRuleData)
!aRuleData->mPresContext->UseDocumentColors();
}
/**
* Tries to call |nsCSSValue::StartImageLoad()| on an image source.
* Image sources are specified by |url()| or |-moz-image-rect()| function.
*/
static void
TryToStartImageLoad(const nsCSSValue& aValue, nsIDocument* aDocument)
{
if (aValue.GetUnit() == eCSSUnit_URL) {
aValue.StartImageLoad(aDocument);
}
else if (aValue.EqualsFunction(eCSSKeyword__moz_image_rect)) {
nsCSSValue::Array* arguments = aValue.GetArrayValue();
NS_ABORT_IF_FALSE(arguments->Count() == 6, "unexpected num of arguments");
const nsCSSValue& image = arguments->Item(1);
if (image.GetUnit() == eCSSUnit_URL)
image.StartImageLoad(aDocument);
}
}
nsresult
nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const
{
@ -180,6 +200,8 @@ nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const
if (!(aRuleData->mSIDs & mStyleBits))
return NS_OK;
nsIDocument* doc = aRuleData->mPresContext->Document();
const char* cursor = Block();
const char* cursor_end = BlockEnd();
while (cursor < cursor_end) {
@ -197,17 +219,12 @@ nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const
const nsCSSValue *val = ValueAtCursor(cursor);
NS_ASSERTION(val->GetUnit() != eCSSUnit_Null, "oops");
if (iProp == eCSSProperty_list_style_image) {
if (val->GetUnit() == eCSSUnit_URL) {
val->StartImageLoad(
aRuleData->mPresContext->Document());
}
TryToStartImageLoad(*val, doc);
} else if (iProp == eCSSProperty_border_image) {
if (val->GetUnit() == eCSSUnit_Array) {
nsCSSValue::Array *array = val->GetArrayValue();
if (array->Item(0).GetUnit() == eCSSUnit_URL) {
array->Item(0).StartImageLoad(
aRuleData->mPresContext->Document());
}
const nsCSSValue& image
= val->GetArrayValue()->Item(0);
TryToStartImageLoad(image, doc);
}
}
*target = *val;
@ -277,20 +294,14 @@ nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const
iProp == eCSSProperty_content) {
for (nsCSSValueList* l = ValueListAtCursor(cursor);
l; l = l->mNext)
if (l->mValue.GetUnit() == eCSSUnit_URL)
l->mValue.StartImageLoad(
aRuleData->mPresContext->Document());
TryToStartImageLoad(l->mValue, doc);
} else if (iProp == eCSSProperty_cursor) {
for (nsCSSValueList* l = ValueListAtCursor(cursor);
l; l = l->mNext)
if (l->mValue.GetUnit() == eCSSUnit_Array) {
// Don't try to restart loads we've already
// started
nsCSSValue& val =
const nsCSSValue& image =
l->mValue.GetArrayValue()->Item(0);
if (val.GetUnit() == eCSSUnit_URL)
val.StartImageLoad(
aRuleData->mPresContext->Document());
TryToStartImageLoad(image, doc);
}
}
// fall through

Просмотреть файл

@ -300,7 +300,15 @@ nsCSSDeclaration::AppendCSSValueToString(nsCSSProperty aProperty,
NS_ASSERTION(array->Count() >= 1, "Functions must have at least one element for the name.");
/* Append the function name. */
AppendCSSValueToString(aProperty, array->Item(0), aResult);
const nsCSSValue& functionName = array->Item(0);
if (functionName.GetUnit() == eCSSUnit_Enumerated) {
// We assume that the first argument is always of nsCSSKeyword type.
const nsCSSKeyword functionId =
static_cast<nsCSSKeyword>(functionName.GetIntValue());
AppendASCIItoUTF16(nsCSSKeywords::GetStringValue(functionId), aResult);
} else {
AppendCSSValueToString(aProperty, functionName, aResult);
}
aResult.AppendLiteral("(");
/* Now, step through the function contents, writing each of them as we go. */

Просмотреть файл

@ -121,6 +121,7 @@ CSS_KEY(-moz-hangul, _moz_hangul)
CSS_KEY(-moz-hyperlinktext, _moz_hyperlinktext)
CSS_KEY(-moz-html-cellhighlight, _moz_html_cellhighlight)
CSS_KEY(-moz-html-cellhighlighttext, _moz_html_cellhighlighttext)
CSS_KEY(-moz-image-rect, _moz_image_rect)
CSS_KEY(-moz-info, _moz_info)
CSS_KEY(-moz-initial, _moz_initial)
CSS_KEY(-moz-inline-box, _moz_inline_box)

Просмотреть файл

@ -111,6 +111,7 @@
#define VARIANT_GRADIENT 0x200000 // eCSSUnit_Gradient
#define VARIANT_CUBIC_BEZIER 0x400000 // CSS transition timing function
#define VARIANT_ALL 0x800000 //
#define VARIANT_IMAGE_RECT 0x01000000 // eCSSUnit_Function
// Common combinations of variants
#define VARIANT_AL (VARIANT_AUTO | VARIANT_LENGTH)
@ -529,9 +530,11 @@ protected:
const PRInt32 aKeywordTable[]);
PRBool ParseCounter(nsCSSValue& aValue);
PRBool ParseAttr(nsCSSValue& aValue);
PRBool SetValueToURL(nsCSSValue& aValue, const nsString& aURL);
PRBool ParseURL(nsCSSValue& aValue);
PRBool TranslateDimension(nsCSSValue& aValue, PRInt32 aVariantMask,
float aNumber, const nsString& aUnit);
PRBool ParseImageRect(nsCSSValue& aImage);
PRBool ParseGradientStop(nsCSSValueGradient* aGradient);
PRBool ParseGradient(nsCSSValue& aValue, PRBool aIsRadial);
@ -1327,7 +1330,8 @@ CSSParserImpl::GetURLInParens(nsString& aURL)
// weren't treated as a URL token by the tokenization
// XXX We really need to push aURL back into the buffer before this
// SkipUntil!
// SkipUntil, but we won't do it as it will make no difference anyway,
// and it will make parsing slower.
SkipUntil(')');
return PR_FALSE;
}
@ -4551,6 +4555,11 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
if (tk->mIdent.LowerCaseEqualsLiteral("-moz-radial-gradient"))
return ParseGradient(aValue, PR_TRUE);
}
if ((aVariantMask & VARIANT_IMAGE_RECT) != 0 &&
eCSSToken_Function == tk->mType &&
tk->mIdent.LowerCaseEqualsLiteral("-moz-image-rect")) {
return ParseImageRect(aValue);
}
if ((aVariantMask & VARIANT_COLOR) != 0) {
if ((mNavQuirkMode && !IsParsingCompoundProperty()) || // NONSTANDARD: Nav interprets 'xxyyzz' values even without '#' prefix
(eCSSToken_ID == tk->mType) ||
@ -4763,7 +4772,7 @@ CSSParserImpl::ParseAttr(nsCSSValue& aValue)
}
PRBool
CSSParserImpl::ParseURL(nsCSSValue& aValue)
CSSParserImpl::SetValueToURL(nsCSSValue& aValue, const nsString& aURL)
{
if (!mSheetPrincipal) {
NS_NOTREACHED("Codepaths that expect to parse URLs MUST pass in an "
@ -4771,16 +4780,12 @@ CSSParserImpl::ParseURL(nsCSSValue& aValue)
return PR_FALSE;
}
nsString url;
if (!GetURLInParens(url))
return PR_FALSE;
// Translate url into an absolute url if the url is relative to the
// style sheet.
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), url, nsnull, mBaseURL);
NS_NewURI(getter_AddRefs(uri), aURL, nsnull, mBaseURL);
nsStringBuffer* buffer = nsCSSValue::BufferFromString(url);
nsStringBuffer* buffer = nsCSSValue::BufferFromString(aURL);
if (NS_UNLIKELY(!buffer)) {
mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY);
return PR_FALSE;
@ -4797,6 +4802,80 @@ CSSParserImpl::ParseURL(nsCSSValue& aValue)
return PR_TRUE;
}
PRBool
CSSParserImpl::ParseURL(nsCSSValue& aValue)
{
nsAutoString url;
if (!GetURLInParens(url))
return PR_FALSE;
return SetValueToURL(aValue, url);
}
/**
* Parse the arguments of -moz-image-rect() function.
* -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
*/
PRBool
CSSParserImpl::ParseImageRect(nsCSSValue& aImage)
{
if (!ExpectSymbol('(', PR_TRUE))
return PR_FALSE;
// A non-iterative for loop to break out when an error occurs.
for (;;) {
nsCSSValue newFunction;
static const PRUint32 kNumArgs = 5;
nsCSSValue::Array* func =
newFunction.InitFunction(eCSSKeyword__moz_image_rect, kNumArgs);
if (!func) {
mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY);
break;
}
// func->Item(0) is reserved for the function name.
nsCSSValue& url = func->Item(1);
nsCSSValue& top = func->Item(2);
nsCSSValue& right = func->Item(3);
nsCSSValue& bottom = func->Item(4);
nsCSSValue& left = func->Item(5);
if (!GetToken(PR_TRUE))
break;
if (mToken.mType == eCSSToken_String) {
if (!SetValueToURL(url, mToken.mIdent))
break;
} else if (mToken.mType == eCSSToken_Function &&
mToken.mIdent.LowerCaseEqualsLiteral("url")) {
if (!ParseURL(url))
break;
} else {
break;
}
if (!ExpectSymbol(',', PR_TRUE))
break;
static const PRInt32 VARIANT_SIDE = VARIANT_NUMBER | VARIANT_PERCENT;
if (!ParseNonNegativeVariant(top, VARIANT_SIDE, nsnull) ||
!ExpectSymbol(',', PR_TRUE) ||
!ParseNonNegativeVariant(right, VARIANT_SIDE, nsnull) ||
!ExpectSymbol(',', PR_TRUE) ||
!ParseNonNegativeVariant(bottom, VARIANT_SIDE, nsnull) ||
!ExpectSymbol(',', PR_TRUE) ||
!ParseNonNegativeVariant(left, VARIANT_SIDE, nsnull) ||
!ExpectSymbol(')', PR_TRUE))
break;
aImage = newFunction;
return PR_TRUE;
}
// If we detect a syntax error, we must match the opening parenthesis of the
// function with the closing parenthesis and skip all the tokens in between.
SkipUntil(')');
return PR_FALSE;
}
PRBool
CSSParserImpl::ParseGradientStop(nsCSSValueGradient* aGradient)
{
@ -5647,7 +5726,9 @@ CSSParserImpl::ParseSingleValueProperty(nsCSSValue& aValue,
return ParseVariant(aValue, VARIANT_HC, nsnull);
case eCSSProperty_background_image:
// Used only internally.
return ParseVariant(aValue, VARIANT_HUO | VARIANT_GRADIENT, nsnull);
return ParseVariant(aValue,
VARIANT_HUO | VARIANT_GRADIENT | VARIANT_IMAGE_RECT,
nsnull);
case eCSSProperty__moz_background_inline_policy:
return ParseVariant(aValue, VARIANT_HK,
nsCSSProps::kBackgroundInlinePolicyKTable);
@ -6430,7 +6511,8 @@ CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundItem& aItem,
} else if (eCSSToken_Function == tt &&
(mToken.mIdent.LowerCaseEqualsLiteral("url") ||
mToken.mIdent.LowerCaseEqualsLiteral("-moz-linear-gradient") ||
mToken.mIdent.LowerCaseEqualsLiteral("-moz-radial-gradient"))) {
mToken.mIdent.LowerCaseEqualsLiteral("-moz-radial-gradient") ||
mToken.mIdent.LowerCaseEqualsLiteral("-moz-image-rect"))) {
if (haveImage)
return PR_FALSE;
haveImage = PR_TRUE;

Просмотреть файл

@ -438,6 +438,37 @@ PRBool nsCSSValue::IsNonTransparentColor() const
(mUnit == eCSSUnit_EnumColor);
}
nsCSSValue::Array*
nsCSSValue::InitFunction(nsCSSKeyword aFunctionId, PRUint32 aNumArgs)
{
nsRefPtr<nsCSSValue::Array> func = Array::Create(aNumArgs + 1);
if (!func) {
return nsnull;
}
func->Item(0).SetIntValue(aFunctionId, eCSSUnit_Enumerated);
SetArrayValue(func, eCSSUnit_Function);
return func;
}
PRBool
nsCSSValue::EqualsFunction(nsCSSKeyword aFunctionId) const
{
if (mUnit != eCSSUnit_Function) {
return PR_FALSE;
}
nsCSSValue::Array* func = mValue.mArray;
NS_ABORT_IF_FALSE(func && func->Count() >= 1 &&
func->Item(0).GetUnit() == eCSSUnit_Enumerated,
"illegally structured function value");
nsCSSKeyword thisFunctionId =
static_cast<nsCSSKeyword>(func->Item(0).GetIntValue());
return thisFunctionId == aFunctionId;
}
// static
nsStringBuffer*
nsCSSValue::BufferFromString(const nsString& aValue)

Просмотреть файл

@ -44,6 +44,7 @@
#include "nsString.h"
#include "nsCoord.h"
#include "nsCSSProperty.h"
#include "nsCSSKeywords.h"
#include "nsIURI.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
@ -334,6 +335,11 @@ public:
NS_HIDDEN_(void) StartImageLoad(nsIDocument* aDocument)
const; // Not really const, but pretending
// Initializes as a function value with the specified function id.
NS_HIDDEN_(Array*) InitFunction(nsCSSKeyword aFunctionId, PRUint32 aNumArgs);
// Checks if this is a function value with the specified function id.
NS_HIDDEN_(PRBool) EqualsFunction(nsCSSKeyword aFunctionId) const;
// Returns an already addrefed buffer. Can return null on allocation
// failure.
static nsStringBuffer* BufferFromString(const nsString& aValue);

Просмотреть файл

@ -1463,6 +1463,87 @@ nsComputedDOMStyle::GetCSSGradientString(const nsStyleGradient* aGradient,
return NS_OK;
}
// -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
nsresult
nsComputedDOMStyle::GetImageRectString(nsIURI* aURI,
const nsStyleSides& aCropRect,
nsString& aString)
{
nsDOMCSSValueList* valueList = GetROCSSValueList(PR_TRUE);
NS_ENSURE_TRUE(valueList, NS_ERROR_OUT_OF_MEMORY);
// <uri>
nsROCSSPrimitiveValue *valURI = GetROCSSPrimitiveValue();
if (!valURI || !valueList->AppendCSSValue(valURI)) {
delete valURI;
delete valueList;
return NS_ERROR_OUT_OF_MEMORY;
}
valURI->SetURI(aURI);
// <top>, <right>, <bottom>, <left>
NS_FOR_CSS_SIDES(side) {
nsROCSSPrimitiveValue *valSide = GetROCSSPrimitiveValue();
if (!valSide || !valueList->AppendCSSValue(valSide)) {
delete valSide;
delete valueList;
return NS_ERROR_OUT_OF_MEMORY;
}
SetValueToCoord(valSide, aCropRect.Get(side));
}
nsAutoString argumentString;
valueList->GetCssText(argumentString);
delete valueList;
aString = NS_LITERAL_STRING("-moz-image-rect(") +
argumentString +
NS_LITERAL_STRING(")");
return NS_OK;
}
nsresult
nsComputedDOMStyle::SetValueToStyleImage(const nsStyleImage& aStyleImage,
nsROCSSPrimitiveValue* aValue)
{
switch (aStyleImage.GetType()) {
case eStyleImageType_Image:
{
imgIRequest *req = aStyleImage.GetImageData();
nsCOMPtr<nsIURI> uri;
req->GetURI(getter_AddRefs(uri));
const nsStyleSides* cropRect = aStyleImage.GetCropRect();
if (cropRect) {
nsAutoString imageRectString;
nsresult rv = GetImageRectString(uri, *cropRect, imageRectString);
NS_ENSURE_SUCCESS(rv, rv);
aValue->SetString(imageRectString);
} else {
aValue->SetURI(uri);
}
break;
}
case eStyleImageType_Gradient:
{
nsAutoString gradientString;
nsresult rv = GetCSSGradientString(aStyleImage.GetGradientData(),
gradientString);
NS_ENSURE_SUCCESS(rv, rv);
aValue->SetString(gradientString);
break;
}
case eStyleImageType_Null:
aValue->SetIdent(eCSSKeyword_none);
break;
default:
NS_NOTREACHED("unexpected image type");
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
nsresult
nsComputedDOMStyle::GetBackgroundImage(nsIDOMCSSValue** aValue)
{
@ -1479,27 +1560,11 @@ nsComputedDOMStyle::GetBackgroundImage(nsIDOMCSSValue** aValue)
return NS_ERROR_OUT_OF_MEMORY;
}
const nsStyleBackground::Image &image = bg->mLayers[i].mImage;
if (image.GetType() == eBackgroundImage_Image) {
imgIRequest *req = image.GetImageData();
if (!req) {
val->SetIdent(eCSSKeyword_none);
} else {
nsCOMPtr<nsIURI> uri;
req->GetURI(getter_AddRefs(uri));
val->SetURI(uri);
}
} else if (image.GetType() == eBackgroundImage_Gradient) {
nsAutoString gradientString;
nsresult rv = GetCSSGradientString(image.GetGradientData(),
gradientString);
if (NS_FAILED(rv)) {
delete valueList;
return rv;
}
val->SetString(gradientString);
} else {
val->SetIdent(eCSSKeyword_none);
const nsStyleImage& image = bg->mLayers[i].mImage;
nsresult rv = SetValueToStyleImage(image, val);
if (NS_FAILED(rv)) {
delete valueList;
return rv;
}
}

Просмотреть файл

@ -144,6 +144,9 @@ private:
nsresult GetCSSGradientString(const nsStyleGradient* aGradient,
nsAString& aString);
nsresult GetImageRectString(nsIURI* aURI,
const nsStyleSides& aCropRect,
nsString& aString);
/* Properties Queryable as CSSValues */
@ -378,6 +381,8 @@ private:
nsROCSSPrimitiveValue* GetROCSSPrimitiveValue();
nsDOMCSSValueList* GetROCSSValueList(PRBool aCommaDelimited);
nsresult SetToRGBAColor(nsROCSSPrimitiveValue* aValue, nscolor aColor);
nsresult SetValueToStyleImage(const nsStyleImage& aStyleImage,
nsROCSSPrimitiveValue* aValue);
/**
* A method to get a percentage base for a percentage value. Returns PR_TRUE

Просмотреть файл

@ -396,6 +396,31 @@ static PRBool SetCoord(const nsCSSValue& aValue, nsStyleCoord& aCoord,
return result;
}
// This inline function offers a shortcut for SetCoord() by refusing to accept
// SETCOORD_LENGTH and SETCOORD_INHERIT masks.
static inline PRBool SetAbsCoord(const nsCSSValue& aValue,
nsStyleCoord& aCoord,
PRInt32 aMask)
{
NS_ABORT_IF_FALSE((aMask & SETCOORD_LH) == 0,
"does not handle SETCOORD_LENGTH and SETCOORD_INHERIT");
// The values of the following variables will never be used; so it does not
// matter what to set.
const nsStyleCoord dummyParentCoord;
nsStyleContext* dummyStyleContext = nsnull;
nsPresContext* dummyPresContext = nsnull;
PRBool dummyCanStoreInRuleTree = PR_TRUE;
PRBool rv = SetCoord(aValue, aCoord, dummyParentCoord, aMask,
dummyStyleContext, dummyPresContext,
dummyCanStoreInRuleTree);
NS_ABORT_IF_FALSE(dummyCanStoreInRuleTree,
"SetCoord() should not modify dummyCanStoreInRuleTree.");
return rv;
}
/* Given an enumerated value that represents a box position, converts it to
* a float representing the percentage of the box it corresponds to. For
* example, "center" becomes 0.5f.
@ -556,6 +581,72 @@ static void SetGradient(const nsCSSValue& aValue, nsPresContext* aPresContext,
}
}
// -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
static void SetStyleImageToImageRect(const nsCSSValue& aValue,
nsStyleImage& aResult)
{
NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Function &&
aValue.EqualsFunction(eCSSKeyword__moz_image_rect),
"the value is not valid -moz-image-rect()");
nsCSSValue::Array* arr = aValue.GetArrayValue();
NS_ABORT_IF_FALSE(arr && arr->Count() == 6, "invalid number of arguments");
// <uri>
if (arr->Item(1).GetUnit() == eCSSUnit_Image) {
aResult.SetImageData(arr->Item(1).GetImageValue());
} else {
NS_WARNING("nsCSSValue::Image::Image() failed?");
}
// <top>, <right>, <bottom>, <left>
nsStyleSides cropRect;
NS_FOR_CSS_SIDES(side) {
nsStyleCoord coord;
const nsCSSValue& val = arr->Item(2 + side);
PRBool unitOk = SetAbsCoord(val, coord, SETCOORD_FACTOR | SETCOORD_PERCENT);
NS_ABORT_IF_FALSE(unitOk, "Incorrect data structure created by CSS parser");
cropRect.Set(side, coord);
}
aResult.SetCropRect(&cropRect);
}
static void SetStyleImage(nsStyleContext* aStyleContext,
const nsCSSValue& aValue,
nsStyleImage& aResult,
PRBool& aCanStoreInRuleTree)
{
aResult.SetNull();
switch (aValue.GetUnit()) {
case eCSSUnit_Image:
aResult.SetImageData(aValue.GetImageValue());
break;
case eCSSUnit_Function:
if (aValue.EqualsFunction(eCSSKeyword__moz_image_rect)) {
SetStyleImageToImageRect(aValue, aResult);
} else {
NS_NOTREACHED("-moz-image-rect() is the only expected function");
}
break;
case eCSSUnit_Gradient:
{
nsStyleGradient* gradient = new nsStyleGradient();
if (gradient) {
SetGradient(aValue, aStyleContext->PresContext(), aStyleContext,
*gradient, aCanStoreInRuleTree);
aResult.SetGradientData(gradient);
}
break;
}
case eCSSUnit_None:
break;
default:
NS_NOTREACHED("unexpected unit; maybe nsCSSValue::Image::Image() failed?");
break;
}
}
// flags for SetDiscrete - align values with SETCOORD_* constants
// where possible
@ -4186,31 +4277,15 @@ struct BackgroundItemComputer<nsCSSValueList, PRUint8>
};
NS_SPECIALIZE_TEMPLATE
struct BackgroundItemComputer<nsCSSValueList, nsStyleBackground::Image>
struct BackgroundItemComputer<nsCSSValueList, nsStyleImage>
{
static void ComputeValue(nsStyleContext* aStyleContext,
const nsCSSValueList* aSpecifiedValue,
nsStyleBackground::Image& aComputedValue,
nsStyleImage& aComputedValue,
PRBool& aCanStoreInRuleTree)
{
const nsCSSValue &value = aSpecifiedValue->mValue;
if (eCSSUnit_Image == value.GetUnit()) {
aComputedValue.SetImageData(value.GetImageValue());
}
else if (eCSSUnit_Gradient == value.GetUnit()) {
nsStyleGradient* gradient = new nsStyleGradient();
if (gradient) {
SetGradient(value, aStyleContext->PresContext(), aStyleContext,
*gradient, aCanStoreInRuleTree);
aComputedValue.SetGradientData(gradient);
} else {
aComputedValue.SetNull();
}
}
else {
NS_ASSERTION(eCSSUnit_None == value.GetUnit(), "unexpected unit");
aComputedValue.SetNull();
}
SetStyleImage(aStyleContext, aSpecifiedValue->mValue, aComputedValue,
aCanStoreInRuleTree);
}
};
@ -4449,7 +4524,7 @@ nsRuleNode::ComputeBackgroundData(void* aStartStruct,
PRBool rebuild = PR_FALSE;
// background-image: url (stored as image), none, inherit [list]
nsStyleBackground::Image initialImage;
nsStyleImage initialImage;
SetBackgroundList(aContext, colorData.mBackImage, bg->mLayers,
parentBG->mLayers, &nsStyleBackground::Layer::mImage,
initialImage, parentBG->mImageCount, bg->mImageCount,
@ -4807,10 +4882,8 @@ nsRuleNode::ComputeBorderData(void* aStartStruct,
// the numbers saying where to split the image
NS_FOR_CSS_SIDES(side) {
// an uninitialized parentCoord is ok because I'm not passing SETCOORD_INHERIT
if (SetCoord(arr->Item(1 + side), coord, nsStyleCoord(),
SETCOORD_FACTOR | SETCOORD_PERCENT, aContext,
mPresContext, canStoreInRuleTree)) {
if (SetAbsCoord(arr->Item(1 + side), coord,
SETCOORD_FACTOR | SETCOORD_PERCENT)) {
border->mBorderImageSplit.Set(side, coord);
}
}

Просмотреть файл

@ -66,6 +66,7 @@
#include "nsBidiUtils.h"
#include "imgIRequest.h"
#include "imgIContainer.h"
#include "prlog.h"
// Make sure we have enough bits in NS_STYLE_INHERIT_MASK.
@ -1318,6 +1319,242 @@ nsStyleGradient::nsStyleGradient(void)
mEndY.SetCoordValue(0);
}
// --------------------
// nsStyleImage
//
nsStyleImage::nsStyleImage()
: mType(eStyleImageType_Null)
, mCropRect(nsnull)
{
MOZ_COUNT_CTOR(nsStyleImage);
}
nsStyleImage::~nsStyleImage()
{
MOZ_COUNT_DTOR(nsStyleImage);
if (mType != eStyleImageType_Null)
SetNull();
}
nsStyleImage::nsStyleImage(const nsStyleImage& aOther)
: mType(eStyleImageType_Null)
, mCropRect(nsnull)
{
// We need our own copy constructor because we don't want
// to copy the reference count
MOZ_COUNT_CTOR(nsStyleImage);
DoCopy(aOther);
}
nsStyleImage&
nsStyleImage::operator=(const nsStyleImage& aOther)
{
if (this != &aOther)
DoCopy(aOther);
return *this;
}
void
nsStyleImage::DoCopy(const nsStyleImage& aOther)
{
SetNull();
if (aOther.mType == eStyleImageType_Image)
SetImageData(aOther.mImage);
else if (aOther.mType == eStyleImageType_Gradient)
SetGradientData(aOther.mGradient);
SetCropRect(aOther.mCropRect);
}
void
nsStyleImage::SetNull()
{
if (mType == eStyleImageType_Gradient)
mGradient->Release();
else if (mType == eStyleImageType_Image)
NS_RELEASE(mImage);
mType = eStyleImageType_Null;
mCropRect = nsnull;
}
void
nsStyleImage::SetImageData(imgIRequest* aImage)
{
NS_IF_ADDREF(aImage);
if (mType != eStyleImageType_Null)
SetNull();
if (aImage) {
mImage = aImage;
mType = eStyleImageType_Image;
}
}
void
nsStyleImage::SetGradientData(nsStyleGradient* aGradient)
{
if (aGradient)
aGradient->AddRef();
if (mType != eStyleImageType_Null)
SetNull();
if (aGradient) {
mGradient = aGradient;
mType = eStyleImageType_Gradient;
}
}
void
nsStyleImage::SetCropRect(nsStyleSides* aCropRect)
{
if (aCropRect) {
mCropRect = new nsStyleSides(*aCropRect);
// There is really not much we can do if 'new' fails
} else {
mCropRect = nsnull;
}
}
static PRInt32
ConvertToPixelCoord(const nsStyleCoord& aCoord, PRInt32 aPercentScale)
{
double pixelValue;
switch (aCoord.GetUnit()) {
case eStyleUnit_Percent:
pixelValue = aCoord.GetPercentValue() * aPercentScale;
break;
case eStyleUnit_Factor:
pixelValue = aCoord.GetFactorValue();
break;
default:
NS_NOTREACHED("unexpected unit for image crop rect");
return 0;
}
NS_ABORT_IF_FALSE(pixelValue >= 0, "we ensured non-negative while parsing");
pixelValue = PR_MIN(pixelValue, PR_INT32_MAX); // avoid overflow
return NS_lround(pixelValue);
}
PRBool
nsStyleImage::ComputeActualCropRect(nsIntRect& aActualCropRect,
PRBool* aIsEntireImage) const
{
if (mType != eStyleImageType_Image)
return PR_FALSE;
nsCOMPtr<imgIContainer> imageContainer;
mImage->GetImage(getter_AddRefs(imageContainer));
if (!imageContainer)
return PR_FALSE;
nsIntSize imageSize;
imageContainer->GetWidth(&imageSize.width);
imageContainer->GetHeight(&imageSize.height);
if (imageSize.width <= 0 || imageSize.height <= 0)
return PR_FALSE;
PRInt32 left = ConvertToPixelCoord(mCropRect->GetLeft(), imageSize.width);
PRInt32 top = ConvertToPixelCoord(mCropRect->GetTop(), imageSize.height);
PRInt32 right = ConvertToPixelCoord(mCropRect->GetRight(), imageSize.width);
PRInt32 bottom = ConvertToPixelCoord(mCropRect->GetBottom(), imageSize.height);
// IntersectRect() returns an empty rect if we get negative width or height
nsIntRect cropRect(left, top, right - left, bottom - top);
nsIntRect imageRect(nsIntPoint(0, 0), imageSize);
aActualCropRect.IntersectRect(imageRect, cropRect);
if (aIsEntireImage)
*aIsEntireImage = (aActualCropRect == imageRect);
return PR_TRUE;
}
PRBool
nsStyleImage::IsOpaque() const
{
if (!IsComplete())
return PR_FALSE;
if (mType == eStyleImageType_Gradient) {
// We could check if every stop color of the gradient is non-transparent.
return PR_FALSE;
}
NS_ABORT_IF_FALSE(mType == eStyleImageType_Image, "unexpected image type");
nsCOMPtr<imgIContainer> imageContainer;
mImage->GetImage(getter_AddRefs(imageContainer));
NS_ABORT_IF_FALSE(imageContainer, "IsComplete() said image container is ready");
// Check if the crop region of the current image frame is opaque
PRBool isOpaque;
if (NS_SUCCEEDED(imageContainer->GetCurrentFrameIsOpaque(&isOpaque)) &&
isOpaque) {
if (!mCropRect)
return PR_TRUE;
// Must make sure if mCropRect contains at least a pixel.
// XXX Is this optimization worth it? Maybe I should just return PR_FALSE.
nsIntRect actualCropRect;
PRBool rv = ComputeActualCropRect(actualCropRect);
NS_ASSERTION(rv, "ComputeActualCropRect() can not fail here");
return rv && !actualCropRect.IsEmpty();
}
return PR_FALSE;
}
PRBool
nsStyleImage::IsComplete() const
{
switch (mType) {
case eStyleImageType_Null:
return PR_FALSE;
case eStyleImageType_Gradient:
return PR_TRUE;
case eStyleImageType_Image:
{
PRUint32 status = imgIRequest::STATUS_ERROR;
return NS_SUCCEEDED(mImage->GetImageStatus(&status)) &&
(status & imgIRequest::STATUS_SIZE_AVAILABLE) &&
(status & imgIRequest::STATUS_FRAME_COMPLETE);
}
default:
NS_NOTREACHED("unexpected image type");
return PR_FALSE;
}
}
static inline PRBool
EqualRects(const nsStyleSides* aRect1, const nsStyleSides* aRect2)
{
return aRect1 == aRect2 || /* handles null== null, and optimize */
(aRect1 && aRect2 && *aRect1 == *aRect2);
}
PRBool
nsStyleImage::operator==(const nsStyleImage& aOther) const
{
if (mType != aOther.mType)
return PR_FALSE;
if (!EqualRects(mCropRect, aOther.mCropRect))
return PR_FALSE;
if (mType == eStyleImageType_Image)
return EqualImages(mImage, aOther.mImage);
if (mType == eStyleImageType_Gradient)
return *mGradient == *aOther.mGradient;
return PR_TRUE;
}
// --------------------
// nsStyleBackground
//
@ -1400,7 +1637,7 @@ PRBool nsStyleBackground::HasFixedBackground() const
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, this) {
const Layer &layer = mLayers[i];
if (layer.mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
layer.mImage.GetType() != eBackgroundImage_Null) {
!layer.mImage.IsEmpty()) {
return PR_TRUE;
}
}
@ -1409,7 +1646,7 @@ PRBool nsStyleBackground::HasFixedBackground() const
PRBool nsStyleBackground::IsTransparent() const
{
return BottomLayer().mImage.GetType() == eBackgroundImage_Null &&
return BottomLayer().mImage.IsEmpty() &&
mImageCount == 1 &&
NS_GET_A(mBackgroundColor) == 0;
}
@ -1494,98 +1731,6 @@ PRBool nsStyleBackground::Layer::operator==(const Layer& aOther) const
mImage == aOther.mImage;
}
nsStyleBackground::Image::Image()
{
MOZ_COUNT_CTOR(nsStyleBackground::Image);
mType = eBackgroundImage_Null;
}
nsStyleBackground::Image::~Image()
{
MOZ_COUNT_DTOR(nsStyleBackground::Image);
if (mType != eBackgroundImage_Null)
SetNull();
}
nsStyleBackground::Image::Image(const nsStyleBackground::Image& aOther)
{
// We need our own copy constructor because we don't want
// to copy the reference count
MOZ_COUNT_CTOR(nsStyleBackground::Image);
mType = eBackgroundImage_Null;
DoCopy(aOther);
}
nsStyleBackground::Image&
nsStyleBackground::Image::operator=(const nsStyleBackground::Image& aOther)
{
if (this != &aOther)
DoCopy(aOther);
return *this;
}
void nsStyleBackground::Image::DoCopy(const nsStyleBackground::Image& aOther)
{
SetNull();
if (aOther.mType == eBackgroundImage_Image)
SetImageData(aOther.mImage);
else if (aOther.mType == eBackgroundImage_Gradient)
SetGradientData(aOther.mGradient);
}
void nsStyleBackground::Image::SetImageData(imgIRequest* aImage)
{
NS_IF_ADDREF(aImage);
if (mType != eBackgroundImage_Null)
SetNull();
if (aImage) {
mImage = aImage;
mType = eBackgroundImage_Image;
}
}
void nsStyleBackground::Image::SetGradientData(nsStyleGradient* aGradient)
{
if (aGradient)
aGradient->AddRef();
if (mType != eBackgroundImage_Null)
SetNull();
if (aGradient) {
mGradient = aGradient;
mType = eBackgroundImage_Gradient;
}
}
void nsStyleBackground::Image::SetNull()
{
if (mType == eBackgroundImage_Gradient)
mGradient->Release();
else if (mType == eBackgroundImage_Image)
NS_RELEASE(mImage);
mType = eBackgroundImage_Null;
}
PRBool nsStyleBackground::Image::operator==(const Image& aOther) const
{
if (mType != aOther.mType)
return PR_FALSE;
if (mType == eBackgroundImage_Image)
return EqualImages(mImage, aOther.mImage);
if (mType == eBackgroundImage_Gradient)
return *mGradient == *aOther.mGradient;
return PR_TRUE;
}
// --------------------
// nsStyleDisplay
//

Просмотреть файл

@ -192,6 +192,106 @@ private:
nsStyleGradient& operator=(const nsStyleGradient& aOther);
};
enum nsStyleImageType {
eStyleImageType_Null,
eStyleImageType_Image,
eStyleImageType_Gradient
};
/**
* Represents a paintable image of one of the following types.
* (1) A real image loaded from an external source.
* (2) A CSS linear or radial gradient.
* (*) Optionally a crop rect can be set to paint a partial (rectangular)
* region of an image. (Currently, this feature is only supported with an
* image of type (1)).
*
* This struct is currently used only for 'background-image', but it may be
* used by other CSS properties such as 'border-image', 'list-style-image', and
* 'content' in the future (bug 507052).
*/
struct nsStyleImage {
nsStyleImage();
~nsStyleImage();
nsStyleImage(const nsStyleImage& aOther);
nsStyleImage& operator=(const nsStyleImage& aOther);
void SetNull();
void SetImageData(imgIRequest* aImage);
void SetGradientData(nsStyleGradient* aGradient);
void SetCropRect(nsStyleSides* aCropRect);
nsStyleImageType GetType() const {
return mType;
}
imgIRequest* GetImageData() const {
NS_ASSERTION(mType == eStyleImageType_Image, "Data is not an image!");
return mImage;
}
nsStyleGradient* GetGradientData() const {
NS_ASSERTION(mType == eStyleImageType_Gradient, "Data is not a gradient!");
return mGradient;
}
nsStyleSides* GetCropRect() const {
NS_ASSERTION(mType == eStyleImageType_Image,
"Only image data can have a crop rect");
return mCropRect;
}
/**
* Compute the actual crop rect in pixels, using the source image bounds.
* The computation involves converting percentage unit to pixel unit and
* clamping each side value to fit in the source image bounds.
* @param aActualCropRect the computed actual crop rect.
* @param aIsEntireImage PR_TRUE iff |aActualCropRect| is identical to the
* source image bounds.
* @return PR_TRUE iff |aActualCropRect| holds a meaningful value.
*/
PRBool ComputeActualCropRect(nsIntRect& aActualCropRect,
PRBool* aIsEntireImage = nsnull) const;
/**
* @return PR_TRUE if the item is definitely opaque --- i.e., paints every
* pixel within its bounds opaquely, and the bounds contains at least a pixel.
*/
PRBool IsOpaque() const;
/**
* @return PR_TRUE if this image is fully loaded, and its size is calculated;
* always returns PR_TRUE if |mType| is |eStyleImageType_Gradient|.
*/
PRBool IsComplete() const;
/**
* @return PR_TRUE if it is 100% confident that this image contains no pixel
* to draw.
*/
PRBool IsEmpty() const {
// There are some other cases when the image will be empty, for example
// when the crop rect is empty. However, checking the emptiness of crop
// rect is non-trivial since each side value can be specified with
// percentage unit, which can not be evaluated until the source image size
// is available. Therefore, we currently postpone the evaluation of crop
// rect until the actual rendering time --- alternatively until IsOpaque()
// is called.
return mType == eStyleImageType_Null;
}
PRBool operator==(const nsStyleImage& aOther) const;
PRBool operator!=(const nsStyleImage& aOther) const {
return !(*this == aOther);
}
private:
void DoCopy(const nsStyleImage& aOther);
nsStyleImageType mType;
union {
imgIRequest* mImage;
nsStyleGradient* mGradient;
};
// This is _currently_ used only in conjunction with eStyleImageType_Image.
nsAutoPtr<nsStyleSides> mCropRect;
};
struct nsStyleColor {
nsStyleColor(nsPresContext* aPresContext);
nsStyleColor(const nsStyleColor& aOther);
@ -217,12 +317,6 @@ struct nsStyleColor {
nscolor mColor; // [inherited]
};
enum nsStyleBackgroundImageType {
eBackgroundImage_Null,
eBackgroundImage_Image,
eBackgroundImage_Gradient
};
struct nsStyleBackground {
nsStyleBackground();
nsStyleBackground(const nsStyleBackground& aOther);
@ -304,46 +398,6 @@ struct nsStyleBackground {
}
};
struct Image;
friend struct Image;
struct Image {
public:
Image();
~Image();
Image(const Image& aOther);
Image& operator=(const Image& aOther);
void SetImageData(imgIRequest* aImage);
void SetGradientData(nsStyleGradient* aGradient);
void SetNull();
nsStyleBackgroundImageType GetType() const {
return mType;
};
imgIRequest* GetImageData() const {
NS_ASSERTION(mType == eBackgroundImage_Image, "Data is not an image!");
return mImage;
};
nsStyleGradient* GetGradientData() const {
NS_ASSERTION(mType == eBackgroundImage_Gradient, "Data is not a gradient!");
return mGradient;
};
PRBool operator==(const Image& aOther) const;
PRBool operator!=(const Image& aOther) const {
return !(*this == aOther);
}
private:
void DoCopy(const Image& aOther);
nsStyleBackgroundImageType mType;
union {
imgIRequest* mImage;
nsStyleGradient* mGradient;
};
};
struct Layer;
friend struct Layer;
struct Layer {
@ -352,7 +406,7 @@ struct nsStyleBackground {
PRUint8 mOrigin; // [reset] See nsStyleConsts.h
PRUint8 mRepeat; // [reset] See nsStyleConsts.h
Position mPosition; // [reset]
Image mImage; // [reset]
nsStyleImage mImage; // [reset]
Size mSize; // [reset]
// Initializes only mImage

Просмотреть файл

@ -202,7 +202,7 @@ TableBackgroundPainter::TableBackgroundData::ShouldSetBCBorder()
}
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, mBackground) {
if (mBackground->mLayers[i].mImage.GetType() != eBackgroundImage_Null)
if (!mBackground->mLayers[i].mImage.IsEmpty())
return PR_TRUE;
}
return PR_FALSE;

Просмотреть файл

@ -4119,7 +4119,7 @@ nsTreeBodyFrame::ScrollInternal(const ScrollParts& aParts, PRInt32 aRow)
// See if we have a transparent background or a background image.
// If we do, then we cannot blit.
const nsStyleBackground* background = GetStyleBackground();
if (background->BottomLayer().mImage.GetType() != eBackgroundImage_Null ||
if (!background->BottomLayer().mImage.IsEmpty() ||
background->mImageCount > 1 ||
NS_GET_A(background->mBackgroundColor) < 255 ||
PR_ABS(delta)*mRowHeight >= mRect.height) {
@ -4178,7 +4178,7 @@ nsTreeBodyFrame::ScrollHorzInternal(const ScrollParts& aParts, PRInt32 aPosition
// See if we have a transparent background or a background image.
// If we do, then we cannot blit.
const nsStyleBackground* background = GetStyleBackground();
if (background->BottomLayer().mImage.GetType() != eBackgroundImage_Null ||
if (!background->BottomLayer().mImage.IsEmpty() ||
background->mImageCount > 1 ||
NS_GET_A(background->mBackgroundColor) < 255 ||
PR_ABS(delta) >= mRect.width) {

Просмотреть файл

@ -59,7 +59,10 @@
// some of the includes make use of internal string types
#define nsAString_h___
#define nsString_h___
#define nsStringFwd_h___
#define nsReadableUtils_h___
class nsACString;
class nsAString;
class nsAFlatString;
class nsAFlatCString;
class nsAdoptingString;