mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Bug 479220 - Implement the CSS gradients proposal. r=roc,dbaron sr=roc
This commit is contained in:
parent
e2d0ef7a15
commit
9b44f1f16c
@ -1513,9 +1513,12 @@ DetermineBackgroundColorInternal(nsPresContext* aPresContext,
|
||||
aDrawBackgroundColor = aPresContext->GetBackgroundColorDraw();
|
||||
}
|
||||
|
||||
aBottomImage = aBackground.BottomLayer().mImage;
|
||||
|
||||
if (!aDrawBackgroundImage || !HaveCompleteBackgroundImage(aBottomImage)) {
|
||||
if (aBackground.BottomLayer().mImage.GetType() == eBackgroundImage_Image) {
|
||||
aBottomImage = aBackground.BottomLayer().mImage.GetImageData();
|
||||
if (!aDrawBackgroundImage || !HaveCompleteBackgroundImage(aBottomImage)) {
|
||||
aBottomImage = nsnull;
|
||||
}
|
||||
} else {
|
||||
aBottomImage = nsnull;
|
||||
}
|
||||
|
||||
@ -1555,6 +1558,84 @@ nsCSSRendering::DetermineBackgroundColor(nsPresContext* aPresContext,
|
||||
bottomImage);
|
||||
}
|
||||
|
||||
static gfxFloat
|
||||
ConvertGradientValueToPixels(const nsStyleCoord& aCoord,
|
||||
nscoord aFillLength,
|
||||
nscoord aAppUnitsPerPixel)
|
||||
{
|
||||
switch (aCoord.GetUnit()) {
|
||||
case eStyleUnit_Percent:
|
||||
return aCoord.GetPercentValue() * aFillLength / aAppUnitsPerPixel;
|
||||
case eStyleUnit_Coord:
|
||||
return aCoord.GetCoordValue() / aAppUnitsPerPixel;
|
||||
default:
|
||||
NS_WARNING("Unexpected coord unit");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
nsStyleGradient* aGradient,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsRect& aOneCellArea,
|
||||
const nsRect& aFillArea,
|
||||
PRBool aRepeat)
|
||||
{
|
||||
gfxContext *ctx = aRenderingContext.ThebesContext();
|
||||
nscoord appUnitsPerPixel = aPresContext->AppUnitsPerDevPixel();
|
||||
|
||||
gfxRect dirtyRect = RectToGfxRect(aDirtyRect, appUnitsPerPixel);
|
||||
gfxRect areaToFill = RectToGfxRect(aFillArea, appUnitsPerPixel);
|
||||
gfxRect oneCellArea = RectToGfxRect(aOneCellArea, appUnitsPerPixel);
|
||||
gfxPoint fillOrigin = oneCellArea.TopLeft();
|
||||
|
||||
areaToFill = areaToFill.Intersect(dirtyRect);
|
||||
if (areaToFill.IsEmpty())
|
||||
return;
|
||||
|
||||
gfxFloat gradX0 = ConvertGradientValueToPixels(aGradient->mStartX,
|
||||
aOneCellArea.width, appUnitsPerPixel);
|
||||
gfxFloat gradY0 = ConvertGradientValueToPixels(aGradient->mStartY,
|
||||
aOneCellArea.height, appUnitsPerPixel);
|
||||
gfxFloat gradX1 = ConvertGradientValueToPixels(aGradient->mEndX,
|
||||
aOneCellArea.width, appUnitsPerPixel);
|
||||
gfxFloat gradY1 = ConvertGradientValueToPixels(aGradient->mEndY,
|
||||
aOneCellArea.height, appUnitsPerPixel);
|
||||
|
||||
nsRefPtr<gfxPattern> gradientPattern;
|
||||
if (aGradient->mIsRadial) {
|
||||
gfxFloat gradRadius0 = double(aGradient->mStartRadius) / appUnitsPerPixel;
|
||||
gfxFloat gradRadius1 = double(aGradient->mEndRadius) / appUnitsPerPixel;
|
||||
gradientPattern = new gfxPattern(gradX0, gradY0, gradRadius0,
|
||||
gradX1, gradY1, gradRadius1);
|
||||
} else {
|
||||
gradientPattern = new gfxPattern(gradX0, gradY0, gradX1, gradY1);
|
||||
}
|
||||
|
||||
if (!gradientPattern || gradientPattern->CairoStatus())
|
||||
return;
|
||||
|
||||
for (PRUint32 i = 0; i < aGradient->mStops.Length(); i++) {
|
||||
gradientPattern->AddColorStop(aGradient->mStops[i].mPosition,
|
||||
gfxRGBA(aGradient->mStops[i].mColor));
|
||||
}
|
||||
|
||||
if (aRepeat)
|
||||
gradientPattern->SetExtend(gfxPattern::EXTEND_REPEAT);
|
||||
|
||||
ctx->Save();
|
||||
ctx->NewPath();
|
||||
// The fill origin is part of the translate call so the pattern starts at
|
||||
// the desired point, rather than (0,0).
|
||||
ctx->Translate(fillOrigin);
|
||||
ctx->SetPattern(gradientPattern);
|
||||
ctx->Rectangle(areaToFill - fillOrigin, PR_TRUE);
|
||||
ctx->Fill();
|
||||
ctx->Restore();
|
||||
}
|
||||
|
||||
void
|
||||
nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
@ -1811,26 +1892,6 @@ PaintBackgroundLayer(nsPresContext* aPresContext,
|
||||
* background-repeat
|
||||
*/
|
||||
|
||||
// Lookup the image
|
||||
imgIRequest *req = aLayer.mImage;
|
||||
if (!HaveCompleteBackgroundImage(req))
|
||||
return;
|
||||
|
||||
nsCOMPtr<imgIContainer> image;
|
||||
req->GetImage(getter_AddRefs(image));
|
||||
req = nsnull;
|
||||
|
||||
nsIntSize imageIntSize;
|
||||
image->GetWidth(&imageIntSize.width);
|
||||
image->GetHeight(&imageIntSize.height);
|
||||
|
||||
nsSize imageSize;
|
||||
imageSize.width = nsPresContext::CSSPixelsToAppUnits(imageIntSize.width);
|
||||
imageSize.height = nsPresContext::CSSPixelsToAppUnits(imageIntSize.height);
|
||||
|
||||
if (imageSize.width == 0 || imageSize.height == 0)
|
||||
return;
|
||||
|
||||
// relative to aBorderArea
|
||||
nsRect bgPositioningArea(0, 0, 0, 0);
|
||||
|
||||
@ -1885,6 +1946,32 @@ 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)
|
||||
return;
|
||||
|
||||
// Compute the anchor point.
|
||||
//
|
||||
// relative to aBorderArea.TopLeft() (which is where the top-left
|
||||
@ -1994,9 +2081,16 @@ PaintBackgroundLayer(nsPresContext* aPresContext,
|
||||
}
|
||||
fillArea.IntersectRect(fillArea, aBGClipRect);
|
||||
|
||||
nsLayoutUtils::DrawImage(&aRenderingContext, image,
|
||||
nsLayoutUtils::GetGraphicsFilterForFrame(aForFrame),
|
||||
destArea, fillArea, anchor + aBorderArea.TopLeft(), aDirtyRect);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -127,6 +127,17 @@ struct nsCSSRendering {
|
||||
const nsRect& aFocusRect,
|
||||
nscolor aColor);
|
||||
|
||||
/**
|
||||
* Render a gradient for an element.
|
||||
*/
|
||||
static void PaintGradient(nsPresContext* aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
nsStyleGradient* aGradient,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsRect& aOneCellArea,
|
||||
const nsRect& aFillArea,
|
||||
PRBool aRepeat);
|
||||
|
||||
/**
|
||||
* Gets the root frame for the frame
|
||||
*/
|
||||
|
@ -562,9 +562,9 @@ nsDisplayBackground::IsOpaque(nsDisplayListBuilder* aBuilder) {
|
||||
return PR_TRUE;
|
||||
|
||||
if (bottomLayer.mRepeat == NS_STYLE_BG_REPEAT_XY) {
|
||||
if (bottomLayer.mImage) {
|
||||
if (bottomLayer.mImage.GetType() == eBackgroundImage_Image) {
|
||||
nsCOMPtr<imgIContainer> container;
|
||||
bottomLayer.mImage->GetImage(getter_AddRefs(container));
|
||||
bottomLayer.mImage.GetImageData()->GetImage(getter_AddRefs(container));
|
||||
if (container) {
|
||||
PRBool animated;
|
||||
container->GetAnimated(&animated);
|
||||
@ -591,7 +591,7 @@ nsDisplayBackground::IsUniform(nsDisplayListBuilder* aBuilder) {
|
||||
nsCSSRendering::FindBackground(mFrame->PresContext(), mFrame, &bg);
|
||||
if (!hasBG)
|
||||
return PR_TRUE;
|
||||
if (!bg->BottomLayer().mImage &&
|
||||
if (bg->BottomLayer().mImage.GetType() == eBackgroundImage_Null &&
|
||||
bg->mImageCount == 1 &&
|
||||
!nsLayoutUtils::HasNonZeroCorner(mFrame->GetStyleBorder()->mBorderRadius) &&
|
||||
bg->BottomLayer().mClip == NS_STYLE_BG_CLIP_BORDER)
|
||||
|
@ -1268,8 +1268,10 @@ nsPresContext::SetupBackgroundImageLoaders(nsIFrame* aFrame,
|
||||
{
|
||||
nsRefPtr<nsImageLoader> loaders;
|
||||
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, aStyleBackground) {
|
||||
imgIRequest *image = aStyleBackground->mLayers[i].mImage;
|
||||
loaders = nsImageLoader::Create(aFrame, image, PR_FALSE, loaders);
|
||||
if (aStyleBackground->mLayers[i].mImage.GetType() == eBackgroundImage_Image) {
|
||||
imgIRequest *image = aStyleBackground->mLayers[i].mImage.GetImageData();
|
||||
loaders = nsImageLoader::Create(aFrame, image, PR_FALSE, loaders);
|
||||
}
|
||||
}
|
||||
SetImageLoaders(aFrame, BACKGROUND_IMAGE, loaders);
|
||||
}
|
||||
|
@ -532,11 +532,8 @@ nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
|
||||
const nsStyleBackground *oldBG = aOldStyleContext->GetStyleBackground();
|
||||
const nsStyleBackground *newBG = GetStyleBackground();
|
||||
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, oldBG) {
|
||||
imgIRequest *oldImage = oldBG->mLayers[i].mImage;
|
||||
imgIRequest *newImage = i < newBG->mImageCount
|
||||
? newBG->mLayers[i].mImage.get()
|
||||
: nsnull;
|
||||
if (oldImage && !EqualImages(oldImage, newImage)) {
|
||||
if (i >= newBG->mImageCount ||
|
||||
oldBG->mLayers[i].mImage != newBG->mLayers[i].mImage) {
|
||||
// stop the image loading for the frame, the image has changed
|
||||
PresContext()->SetImageLoaders(this,
|
||||
nsPresContext::BACKGROUND_IMAGE, nsnull);
|
||||
@ -4092,7 +4089,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 &&
|
||||
if (layer.mImage.GetType() != eBackgroundImage_Null &&
|
||||
(layer.mPosition.mXIsPercent || layer.mPosition.mYIsPercent)) {
|
||||
Invalidate(nsRect(0, 0, aOldRect.width, aOldRect.height));
|
||||
return;
|
||||
|
23
layout/reftests/css-gradients/linear-keywords-ref.html
Normal file
23
layout/reftests/css-gradients/linear-keywords-ref.html
Normal file
@ -0,0 +1,23 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
class="reftest-wait">
|
||||
<head>
|
||||
<script>
|
||||
function doDraw() {
|
||||
var ctx = document.getElementById('canvas').getContext('2d');
|
||||
|
||||
var grad = ctx.createLinearGradient(0,0,150,300);
|
||||
grad.addColorStop(0, '#0000ff');
|
||||
grad.addColorStop(1, '#000000');
|
||||
|
||||
ctx.fillStyle = grad;
|
||||
ctx.fillRect(0,0,300,300);
|
||||
|
||||
document.documentElement.removeAttribute('class');
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="doDraw();">
|
||||
<canvas id="canvas" width="300" height="300"/>
|
||||
</body>
|
||||
</html>
|
||||
|
1
layout/reftests/css-gradients/linear-keywords.html
Normal file
1
layout/reftests/css-gradients/linear-keywords.html
Normal file
@ -0,0 +1 @@
|
||||
<div style="background: -moz-linear-gradient(left top, center bottom, from(#0000ff), to(#000000)) no-repeat; width: 300px; height: 300px;"><br></div>
|
34
layout/reftests/css-gradients/linear-mix-ref.html
Normal file
34
layout/reftests/css-gradients/linear-mix-ref.html
Normal file
@ -0,0 +1,34 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
class="reftest-wait">
|
||||
<head>
|
||||
<script>
|
||||
function doDraw() {
|
||||
var ctx = document.getElementById('canvas').getContext('2d');
|
||||
|
||||
var grad = ctx.createLinearGradient(150,20,270,130);
|
||||
grad.addColorStop(0, '#0000ff');
|
||||
grad.addColorStop(1, '#000000');
|
||||
|
||||
ctx.fillStyle = grad;
|
||||
ctx.fillRect(0,0,300,300);
|
||||
|
||||
ctx = document.getElementById('canvas2').getContext('2d');
|
||||
|
||||
grad = ctx.createLinearGradient(30,300,300,50);
|
||||
grad.addColorStop(0, '#00ff00');
|
||||
grad.addColorStop(1, '#000000');
|
||||
|
||||
ctx.fillStyle = grad;
|
||||
ctx.fillRect(0,0,300,300);
|
||||
|
||||
document.documentElement.removeAttribute('class');
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="doDraw();">
|
||||
<canvas id="canvas" width="300" height="300"></canvas>
|
||||
<br/><br/>
|
||||
<canvas id="canvas2" width="300" height="300"></canvas>
|
||||
</body>
|
||||
</html>
|
||||
|
3
layout/reftests/css-gradients/linear-mix.html
Normal file
3
layout/reftests/css-gradients/linear-mix.html
Normal file
@ -0,0 +1,3 @@
|
||||
<div style="background: -moz-linear-gradient(center 20px, 90% 130px, from(#0000ff), to(#000000)) no-repeat; width: 300px; height: 300px;"><br></div>
|
||||
<br>
|
||||
<div style="background: -moz-linear-gradient(10% bottom, right 50px, from(#00ff00), to(#000000)) no-repeat; width: 300px; height: 300px;"><br></div>
|
23
layout/reftests/css-gradients/linear-percent-ref.html
Normal file
23
layout/reftests/css-gradients/linear-percent-ref.html
Normal file
@ -0,0 +1,23 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
class="reftest-wait">
|
||||
<head>
|
||||
<script>
|
||||
function doDraw() {
|
||||
var ctx = document.getElementById('canvas').getContext('2d');
|
||||
|
||||
var grad = ctx.createLinearGradient(30,60,240,270);
|
||||
grad.addColorStop(0, '#0000ff');
|
||||
grad.addColorStop(1, '#000000');
|
||||
|
||||
ctx.fillStyle = grad;
|
||||
ctx.fillRect(0,0,300,300);
|
||||
|
||||
document.documentElement.removeAttribute('class');
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="doDraw();">
|
||||
<canvas id="canvas" width="300" height="300"/>
|
||||
</body>
|
||||
</html>
|
||||
|
1
layout/reftests/css-gradients/linear-percent.html
Normal file
1
layout/reftests/css-gradients/linear-percent.html
Normal file
@ -0,0 +1 @@
|
||||
<div style="background: -moz-linear-gradient(10% 20%, 80% 90%, from(#0000ff), to(#000000)) no-repeat; width: 300px; height: 300px;"><br></div>
|
24
layout/reftests/css-gradients/linear-ref.html
Normal file
24
layout/reftests/css-gradients/linear-ref.html
Normal file
@ -0,0 +1,24 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
class="reftest-wait">
|
||||
<head>
|
||||
<script>
|
||||
function doDraw() {
|
||||
var ctx = document.getElementById('canvas').getContext('2d');
|
||||
|
||||
var grad = ctx.createLinearGradient(10,20,50,100);
|
||||
grad.addColorStop(0, 'red');
|
||||
grad.addColorStop(1, 'rgb(100, 200, 0)');
|
||||
grad.addColorStop(0.5, '#7777FF');
|
||||
|
||||
ctx.fillStyle = grad;
|
||||
ctx.fillRect(0,0,300,300);
|
||||
|
||||
document.documentElement.removeAttribute('class');
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="doDraw();">
|
||||
<canvas id="canvas" width="300" height="300"/>
|
||||
</body>
|
||||
</html>
|
||||
|
1
layout/reftests/css-gradients/linear.html
Normal file
1
layout/reftests/css-gradients/linear.html
Normal file
@ -0,0 +1 @@
|
||||
<div style="background: -moz-linear-gradient(10px 20px, 50px 100px, from(red), to(rgb(100, 200, 0)), color-stop(0.5, #7777FF)) no-repeat; width: 300px; height: 300px;"><br></div>
|
21
layout/reftests/css-gradients/nostops-ref.html
Normal file
21
layout/reftests/css-gradients/nostops-ref.html
Normal file
@ -0,0 +1,21 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
class="reftest-wait">
|
||||
<head>
|
||||
<script>
|
||||
function doDraw() {
|
||||
var ctx = document.getElementById('canvas').getContext('2d');
|
||||
|
||||
var grad = ctx.createLinearGradient(0,0,150,300);
|
||||
|
||||
ctx.fillStyle = grad;
|
||||
ctx.fillRect(0,0,300,300);
|
||||
|
||||
document.documentElement.removeAttribute('class');
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="doDraw();">
|
||||
<canvas id="canvas" width="300" height="300"/>
|
||||
</body>
|
||||
</html>
|
||||
|
1
layout/reftests/css-gradients/nostops.html
Normal file
1
layout/reftests/css-gradients/nostops.html
Normal file
@ -0,0 +1 @@
|
||||
<div style="background: -moz-linear-gradient(left top, center bottom) no-repeat; width: 300px; height: 300px;"><br></div>
|
22
layout/reftests/css-gradients/onestop-ref.html
Normal file
22
layout/reftests/css-gradients/onestop-ref.html
Normal file
@ -0,0 +1,22 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
class="reftest-wait">
|
||||
<head>
|
||||
<script>
|
||||
function doDraw() {
|
||||
var ctx = document.getElementById('canvas').getContext('2d');
|
||||
|
||||
var grad = ctx.createLinearGradient(0,0,150,300);
|
||||
grad.addColorStop(0.5, '#0000ff');
|
||||
|
||||
ctx.fillStyle = grad;
|
||||
ctx.fillRect(0,0,300,300);
|
||||
|
||||
document.documentElement.removeAttribute('class');
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="doDraw();">
|
||||
<canvas id="canvas" width="300" height="300"/>
|
||||
</body>
|
||||
</html>
|
||||
|
1
layout/reftests/css-gradients/onestop.html
Normal file
1
layout/reftests/css-gradients/onestop.html
Normal file
@ -0,0 +1 @@
|
||||
<div style="background: -moz-linear-gradient(left top, center bottom, color-stop(0.5, #0000ff)) no-repeat; width: 300px; height: 300px;"><br></div>
|
24
layout/reftests/css-gradients/radial-ref.html
Normal file
24
layout/reftests/css-gradients/radial-ref.html
Normal file
@ -0,0 +1,24 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
class="reftest-wait">
|
||||
<head>
|
||||
<script>
|
||||
function doDraw() {
|
||||
var ctx = document.getElementById('canvas').getContext('2d');
|
||||
|
||||
var radgrad = ctx.createRadialGradient(45,45,10,52,50,30);
|
||||
radgrad.addColorStop(0, '#A7D30C');
|
||||
radgrad.addColorStop(0.9, '#019F62');
|
||||
radgrad.addColorStop(1, 'rgba(1,159,98,0)');
|
||||
|
||||
ctx.fillStyle = radgrad;
|
||||
ctx.fillRect(0,0,150,150);
|
||||
|
||||
document.documentElement.removeAttribute('class');
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="doDraw();">
|
||||
<canvas id="canvas" width="300" height="300"/>
|
||||
</body>
|
||||
</html>
|
||||
|
1
layout/reftests/css-gradients/radial.html
Normal file
1
layout/reftests/css-gradients/radial.html
Normal file
@ -0,0 +1 @@
|
||||
<div style="background: -moz-radial-gradient(45px 45px, 10px, 52px 50px, 30px, from(#a7d30c), color-stop(90%, #019f62), to(rgba(1, 159, 98, 0))) no-repeat; width: 300px; height: 300px;"><br></div>
|
8
layout/reftests/css-gradients/reftest.list
Normal file
8
layout/reftests/css-gradients/reftest.list
Normal file
@ -0,0 +1,8 @@
|
||||
== linear.html linear-ref.html
|
||||
== radial.html radial-ref.html
|
||||
== linear-keywords.html linear-keywords-ref.html
|
||||
== linear-percent.html linear-percent-ref.html
|
||||
== linear-mix.html linear-mix-ref.html
|
||||
== nostops.html nostops-ref.html
|
||||
== onestop.html onestop-ref.html
|
||||
== twostops.html twostops-ref.html
|
23
layout/reftests/css-gradients/twostops-ref.html
Normal file
23
layout/reftests/css-gradients/twostops-ref.html
Normal file
@ -0,0 +1,23 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
class="reftest-wait">
|
||||
<head>
|
||||
<script>
|
||||
function doDraw() {
|
||||
var ctx = document.getElementById('canvas').getContext('2d');
|
||||
|
||||
var grad = ctx.createLinearGradient(0,0,150,300);
|
||||
grad.addColorStop(0.5, '#0000ff');
|
||||
grad.addColorStop(0.5, '#ff0000');
|
||||
|
||||
ctx.fillStyle = grad;
|
||||
ctx.fillRect(0,0,300,300);
|
||||
|
||||
document.documentElement.removeAttribute('class');
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="doDraw();">
|
||||
<canvas id="canvas" width="300" height="300"/>
|
||||
</body>
|
||||
</html>
|
||||
|
1
layout/reftests/css-gradients/twostops.html
Normal file
1
layout/reftests/css-gradients/twostops.html
Normal file
@ -0,0 +1 @@
|
||||
<div style="background: -moz-linear-gradient(left top, center bottom, color-stop(0.5, #0000ff), color-stop(0.5, #ff0000)) no-repeat; width: 300px; height: 300px;"><br></div>
|
@ -41,6 +41,9 @@ include css-import/reftest.list
|
||||
# css character encoding tests
|
||||
include css-charset/reftest.list
|
||||
|
||||
# css gradients
|
||||
include css-gradients/reftest.list
|
||||
|
||||
# css media queries (tests for print mode)
|
||||
include css-mediaqueries/reftest.list
|
||||
|
||||
|
@ -413,6 +413,49 @@ nsCSSDeclaration::AppendCSSValueToString(nsCSSProperty aProperty,
|
||||
tmpStr.AppendFloat(aValue.GetFloatValue());
|
||||
aResult.Append(tmpStr);
|
||||
}
|
||||
else if (eCSSUnit_Gradient == unit) {
|
||||
nsCSSValueGradient* gradient = aValue.GetGradientValue();
|
||||
|
||||
if (gradient->mIsRadial)
|
||||
aResult.AppendLiteral("-moz-radial-gradient(");
|
||||
else
|
||||
aResult.AppendLiteral("-moz-linear-gradient(");
|
||||
|
||||
AppendCSSValueToString(eCSSProperty_background_position,
|
||||
gradient->mStartX, aResult);
|
||||
aResult.AppendLiteral(" ");
|
||||
|
||||
AppendCSSValueToString(eCSSProperty_background_position,
|
||||
gradient->mStartY, aResult);
|
||||
aResult.AppendLiteral(", ");
|
||||
|
||||
if (gradient->mIsRadial) {
|
||||
AppendCSSValueToString(aProperty, gradient->mStartRadius, aResult);
|
||||
aResult.AppendLiteral(", ");
|
||||
}
|
||||
|
||||
AppendCSSValueToString(eCSSProperty_background_position,
|
||||
gradient->mEndX, aResult);
|
||||
aResult.AppendLiteral(" ");
|
||||
|
||||
AppendCSSValueToString(eCSSProperty_background_position,
|
||||
gradient->mEndY, aResult);
|
||||
|
||||
if (gradient->mIsRadial) {
|
||||
aResult.AppendLiteral(", ");
|
||||
AppendCSSValueToString(aProperty, gradient->mEndRadius, aResult);
|
||||
}
|
||||
|
||||
for (PRUint32 i = 0; i < gradient->mStops.Length(); i++) {
|
||||
aResult.AppendLiteral(", color-stop(");
|
||||
AppendCSSValueToString(aProperty, gradient->mStops[i].mLocation, aResult);
|
||||
aResult.AppendLiteral(", ");
|
||||
AppendCSSValueToString(aProperty, gradient->mStops[i].mColor, aResult);
|
||||
aResult.AppendLiteral(")");
|
||||
}
|
||||
|
||||
aResult.AppendLiteral(")");
|
||||
}
|
||||
|
||||
switch (unit) {
|
||||
case eCSSUnit_Null: break;
|
||||
@ -446,6 +489,7 @@ nsCSSDeclaration::AppendCSSValueToString(nsCSSProperty aProperty,
|
||||
case eCSSUnit_Color: break;
|
||||
case eCSSUnit_Percent: aResult.Append(PRUnichar('%')); break;
|
||||
case eCSSUnit_Number: break;
|
||||
case eCSSUnit_Gradient: break;
|
||||
|
||||
case eCSSUnit_Inch: aResult.AppendLiteral("in"); break;
|
||||
case eCSSUnit_Millimeter: aResult.AppendLiteral("mm"); break;
|
||||
|
@ -66,7 +66,6 @@
|
||||
#include "nsIAtom.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsColor.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsCSSPseudoClasses.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsCSSAnonBoxes.h"
|
||||
@ -107,6 +106,7 @@
|
||||
#define VARIANT_NONE 0x040000 // O
|
||||
#define VARIANT_NORMAL 0x080000 // M
|
||||
#define VARIANT_SYSFONT 0x100000 // eCSSUnit_System_Font
|
||||
#define VARIANT_GRADIENT 0x200000 // eCSSUnit_Gradient
|
||||
|
||||
// Common combinations of variants
|
||||
#define VARIANT_AL (VARIANT_AUTO | VARIANT_LENGTH)
|
||||
@ -422,7 +422,7 @@ protected:
|
||||
|
||||
PRBool ParseBackgroundList(nsCSSProperty aPropID); // a single value prop-id
|
||||
PRBool ParseBackgroundPosition();
|
||||
PRBool ParseBoxPositionValues(nsCSSValuePair& aOut);
|
||||
PRBool ParseBoxPositionValues(nsCSSValuePair& aOut, PRBool aAcceptsInherit);
|
||||
PRBool ParseBackgroundSize();
|
||||
PRBool ParseBackgroundSizeValues(nsCSSValuePair& aOut);
|
||||
PRBool ParseBorderColor();
|
||||
@ -510,6 +510,8 @@ protected:
|
||||
PRBool ParseURL(nsCSSValue& aValue);
|
||||
PRBool TranslateDimension(nsCSSValue& aValue, PRInt32 aVariantMask,
|
||||
float aNumber, const nsString& aUnit);
|
||||
PRBool ParseGradientStop(nsCSSValueGradient* aGradient);
|
||||
PRBool ParseGradient(nsCSSValue& aValue, PRBool aIsRadial);
|
||||
|
||||
void SetParsingCompoundProperty(PRBool aBool) {
|
||||
NS_ASSERTION(aBool == PR_TRUE || aBool == PR_FALSE, "bad PRBool value");
|
||||
@ -4513,6 +4515,15 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
if ((aVariantMask & VARIANT_GRADIENT) != 0 &&
|
||||
eCSSToken_Function == tk->mType) {
|
||||
// a generated gradient
|
||||
if (tk->mIdent.LowerCaseEqualsLiteral("-moz-linear-gradient"))
|
||||
return ParseGradient(aValue, PR_FALSE);
|
||||
|
||||
if (tk->mIdent.LowerCaseEqualsLiteral("-moz-radial-gradient"))
|
||||
return ParseGradient(aValue, PR_TRUE);
|
||||
}
|
||||
if ((aVariantMask & VARIANT_COLOR) != 0) {
|
||||
if ((mNavQuirkMode && !IsParsingCompoundProperty()) || // NONSTANDARD: Nav interprets 'xxyyzz' values even without '#' prefix
|
||||
(eCSSToken_ID == tk->mType) ||
|
||||
@ -4762,6 +4773,181 @@ CSSParserImpl::ParseURL(nsCSSValue& aValue)
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
CSSParserImpl::ParseGradientStop(nsCSSValueGradient* aGradient)
|
||||
{
|
||||
if (!GetToken(PR_TRUE))
|
||||
return PR_FALSE;
|
||||
|
||||
if (eCSSToken_Function != mToken.mType) {
|
||||
UngetToken();
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (mToken.mIdent.LowerCaseEqualsLiteral("from")) {
|
||||
// Start of the gradient
|
||||
if (!ExpectSymbol('(', PR_FALSE)) {
|
||||
NS_ABORT_IF_FALSE(PR_FALSE, "function token without (");
|
||||
}
|
||||
|
||||
nsCSSValue fromFloat(0.0f, eCSSUnit_Percent);
|
||||
nsCSSValue fromColor;
|
||||
if (!ParseVariant(fromColor, VARIANT_COLOR, nsnull)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (!ExpectSymbol(')', PR_TRUE)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
aGradient->mStops.AppendElement(nsCSSValueGradientStop(fromFloat, fromColor));
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (mToken.mIdent.LowerCaseEqualsLiteral("to")) {
|
||||
// End of the gradient
|
||||
if (!ExpectSymbol('(', PR_FALSE)) {
|
||||
NS_ABORT_IF_FALSE(PR_FALSE, "function token without (");
|
||||
}
|
||||
|
||||
nsCSSValue toFloat(1.0f, eCSSUnit_Percent);
|
||||
nsCSSValue toColor;
|
||||
if (!ParseVariant(toColor, VARIANT_COLOR, nsnull)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (!ExpectSymbol(')', PR_TRUE)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
aGradient->mStops.AppendElement(nsCSSValueGradientStop(toFloat, toColor));
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (mToken.mIdent.LowerCaseEqualsLiteral("color-stop")) {
|
||||
// Some kind of gradient stop, somewhere...
|
||||
if (!ExpectSymbol('(', PR_FALSE)) {
|
||||
NS_ABORT_IF_FALSE(PR_FALSE, "function token without (");
|
||||
}
|
||||
|
||||
nsCSSValue stopFloat;
|
||||
if (!ParseVariant(stopFloat, VARIANT_PERCENT | VARIANT_NUMBER, nsnull)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// Check for a sane position value, and clamp it if it isn't
|
||||
if (stopFloat.GetUnit() == eCSSUnit_Percent) {
|
||||
if (stopFloat.GetPercentValue() > 1.0)
|
||||
stopFloat.SetPercentValue(1.0);
|
||||
else if (stopFloat.GetPercentValue() < 0.0)
|
||||
stopFloat.SetPercentValue(0.0);
|
||||
} else {
|
||||
if (stopFloat.GetFloatValue() > 1.0)
|
||||
stopFloat.SetFloatValue(1.0, eCSSUnit_Number);
|
||||
else if (stopFloat.GetFloatValue() < 0.0)
|
||||
stopFloat.SetFloatValue(0.0, eCSSUnit_Number);
|
||||
}
|
||||
|
||||
if (!ExpectSymbol(',', PR_TRUE)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsCSSValue stopColor;
|
||||
if (!ParseVariant(stopColor, VARIANT_COLOR, nsnull)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (!ExpectSymbol(')', PR_TRUE)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
aGradient->mStops.AppendElement(nsCSSValueGradientStop(stopFloat, stopColor));
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// No idea what this is
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
CSSParserImpl::ParseGradient(nsCSSValue& aValue,
|
||||
PRBool aIsRadial)
|
||||
{
|
||||
if (!ExpectSymbol('(', PR_FALSE)) {
|
||||
NS_ABORT_IF_FALSE(PR_FALSE, "function token without (");
|
||||
}
|
||||
|
||||
nsCSSValuePair startPos;
|
||||
if (!ParseBoxPositionValues(startPos, PR_FALSE))
|
||||
return PR_FALSE;
|
||||
|
||||
if (!ExpectSymbol(',', PR_TRUE)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsCSSValue startRadius;
|
||||
if (aIsRadial) {
|
||||
if (!ParseNonNegativeVariant(startRadius, VARIANT_LENGTH, nsnull)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (!ExpectSymbol(',', PR_TRUE)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
nsCSSValuePair endPos;
|
||||
if (!ParseBoxPositionValues(endPos, PR_FALSE)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsCSSValue endRadius;
|
||||
if (aIsRadial) {
|
||||
if (!ExpectSymbol(',', PR_TRUE)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (!ParseNonNegativeVariant(endRadius, VARIANT_LENGTH, nsnull)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<nsCSSValueGradient> cssGradient =
|
||||
new nsCSSValueGradient(aIsRadial, startPos.mXValue, startPos.mYValue,
|
||||
startRadius, endPos.mXValue, endPos.mYValue,
|
||||
endRadius);
|
||||
|
||||
// Do optional stop functions
|
||||
while (ExpectSymbol(',', PR_TRUE)) {
|
||||
if (!ParseGradientStop(cssGradient)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ExpectSymbol(')', PR_TRUE)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
aValue.SetGradientValue(cssGradient);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRInt32
|
||||
CSSParserImpl::ParseChoice(nsCSSValue aValues[],
|
||||
const nsCSSProperty aPropIDs[], PRInt32 aNumIDs)
|
||||
@ -5421,7 +5607,7 @@ CSSParserImpl::ParseSingleValueProperty(nsCSSValue& aValue,
|
||||
return ParseVariant(aValue, VARIANT_HC, nsnull);
|
||||
case eCSSProperty_background_image:
|
||||
// Used only internally.
|
||||
return ParseVariant(aValue, VARIANT_HUO, nsnull);
|
||||
return ParseVariant(aValue, VARIANT_HUO | VARIANT_GRADIENT, nsnull);
|
||||
case eCSSProperty__moz_background_inline_policy:
|
||||
return ParseVariant(aValue, VARIANT_HK,
|
||||
nsCSSProps::kBackgroundInlinePolicyKTable);
|
||||
@ -6155,7 +6341,7 @@ CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundItem& aItem,
|
||||
if (havePosition)
|
||||
return PR_FALSE;
|
||||
havePosition = PR_TRUE;
|
||||
if (!ParseBoxPositionValues(aItem.mPosition)) {
|
||||
if (!ParseBoxPositionValues(aItem.mPosition, PR_FALSE)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
#if 0
|
||||
@ -6202,7 +6388,9 @@ CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundItem& aItem,
|
||||
aItem.mLastItem = PR_TRUE;
|
||||
}
|
||||
} else if (eCSSToken_Function == tt &&
|
||||
mToken.mIdent.LowerCaseEqualsLiteral("url")) {
|
||||
(mToken.mIdent.LowerCaseEqualsLiteral("url") ||
|
||||
mToken.mIdent.LowerCaseEqualsLiteral("-moz-linear-gradient") ||
|
||||
mToken.mIdent.LowerCaseEqualsLiteral("-moz-radial-gradient"))) {
|
||||
if (haveImage)
|
||||
return PR_FALSE;
|
||||
haveImage = PR_TRUE;
|
||||
@ -6214,7 +6402,7 @@ CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundItem& aItem,
|
||||
if (havePosition)
|
||||
return PR_FALSE;
|
||||
havePosition = PR_TRUE;
|
||||
if (!ParseBoxPositionValues(aItem.mPosition)) {
|
||||
if (!ParseBoxPositionValues(aItem.mPosition, PR_FALSE)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
} else {
|
||||
@ -6285,15 +6473,11 @@ CSSParserImpl::ParseBackgroundPosition()
|
||||
nsCSSValuePair valuePair;
|
||||
nsCSSValuePairList *head = nsnull, **tail = &head;
|
||||
for (;;) {
|
||||
if (!ParseBoxPositionValues(valuePair)) {
|
||||
if (!ParseBoxPositionValues(valuePair, !head)) {
|
||||
break;
|
||||
}
|
||||
PRBool inheritOrInitial = valuePair.mXValue.GetUnit() == eCSSUnit_Inherit ||
|
||||
valuePair.mXValue.GetUnit() == eCSSUnit_Initial;
|
||||
if (inheritOrInitial && head) {
|
||||
// inherit and initial are only allowed on their own
|
||||
break;
|
||||
}
|
||||
nsCSSValuePairList *item = new nsCSSValuePairList;
|
||||
if (!item) {
|
||||
mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY);
|
||||
@ -6323,14 +6507,17 @@ CSSParserImpl::ParseBackgroundPosition()
|
||||
* like "top," "left center," etc.
|
||||
*
|
||||
* @param aOut The nsCSSValuePair in which to place the result.
|
||||
* @param aAcceptsInherit If true, 'inherit' and 'initial' are legal values
|
||||
* @return Whether or not the operation succeeded.
|
||||
*/
|
||||
PRBool CSSParserImpl::ParseBoxPositionValues(nsCSSValuePair &aOut)
|
||||
PRBool CSSParserImpl::ParseBoxPositionValues(nsCSSValuePair &aOut,
|
||||
PRBool aAcceptsInherit)
|
||||
{
|
||||
// First try a percentage or a length value
|
||||
nsCSSValue &xValue = aOut.mXValue,
|
||||
&yValue = aOut.mYValue;
|
||||
if (ParseVariant(xValue, VARIANT_HLP, nsnull)) {
|
||||
PRInt32 variantMask = aAcceptsInherit ? VARIANT_HLP : VARIANT_LP;
|
||||
if (ParseVariant(xValue, variantMask, nsnull)) {
|
||||
if (eCSSUnit_Inherit == xValue.GetUnit() ||
|
||||
eCSSUnit_Initial == xValue.GetUnit()) { // both are inherited or both are set to initial
|
||||
yValue = xValue;
|
||||
@ -7585,7 +7772,7 @@ PRBool CSSParserImpl::ParseMozTransform()
|
||||
PRBool CSSParserImpl::ParseMozTransformOrigin()
|
||||
{
|
||||
/* Read in a box position, fail if we can't. */
|
||||
if (!ParseBoxPositionValues(mTempData.mDisplay.mTransformOrigin) ||
|
||||
if (!ParseBoxPositionValues(mTempData.mDisplay.mTransformOrigin, PR_TRUE) ||
|
||||
!ExpectEndProperty())
|
||||
return PR_FALSE;
|
||||
|
||||
|
@ -124,6 +124,13 @@ nsCSSValue::nsCSSValue(nsCSSValue::Image* aValue)
|
||||
mValue.mImage->AddRef();
|
||||
}
|
||||
|
||||
nsCSSValue::nsCSSValue(nsCSSValueGradient* aValue)
|
||||
: mUnit(eCSSUnit_Gradient)
|
||||
{
|
||||
mValue.mGradient = aValue;
|
||||
mValue.mGradient->AddRef();
|
||||
}
|
||||
|
||||
nsCSSValue::nsCSSValue(const nsCSSValue& aCopy)
|
||||
: mUnit(aCopy.mUnit)
|
||||
{
|
||||
@ -155,6 +162,10 @@ nsCSSValue::nsCSSValue(const nsCSSValue& aCopy)
|
||||
mValue.mImage = aCopy.mValue.mImage;
|
||||
mValue.mImage->AddRef();
|
||||
}
|
||||
else if (eCSSUnit_Gradient == mUnit) {
|
||||
mValue.mGradient = aCopy.mValue.mGradient;
|
||||
mValue.mGradient->AddRef();
|
||||
}
|
||||
else {
|
||||
NS_NOTREACHED("unknown unit");
|
||||
}
|
||||
@ -194,6 +205,9 @@ PRBool nsCSSValue::operator==(const nsCSSValue& aOther) const
|
||||
else if (eCSSUnit_Image == mUnit) {
|
||||
return *mValue.mImage == *aOther.mValue.mImage;
|
||||
}
|
||||
else if (eCSSUnit_Gradient == mUnit) {
|
||||
return *mValue.mGradient == *aOther.mValue.mGradient;
|
||||
}
|
||||
else {
|
||||
return mValue.mFloat == aOther.mValue.mFloat;
|
||||
}
|
||||
@ -243,6 +257,8 @@ void nsCSSValue::DoReset()
|
||||
mValue.mURL->Release();
|
||||
} else if (eCSSUnit_Image == mUnit) {
|
||||
mValue.mImage->Release();
|
||||
} else if (eCSSUnit_Gradient == mUnit) {
|
||||
mValue.mGradient->Release();
|
||||
}
|
||||
mUnit = eCSSUnit_Null;
|
||||
}
|
||||
@ -326,6 +342,14 @@ void nsCSSValue::SetImageValue(nsCSSValue::Image* aValue)
|
||||
mValue.mImage->AddRef();
|
||||
}
|
||||
|
||||
void nsCSSValue::SetGradientValue(nsCSSValueGradient* aValue)
|
||||
{
|
||||
Reset();
|
||||
mUnit = eCSSUnit_Gradient;
|
||||
mValue.mGradient = aValue;
|
||||
mValue.mGradient->AddRef();
|
||||
}
|
||||
|
||||
void nsCSSValue::SetAutoValue()
|
||||
{
|
||||
Reset();
|
||||
@ -439,15 +463,12 @@ nsCSSValue::URL::URL(nsIURI* aURI, nsStringBuffer* aString, nsIURI* aReferrer,
|
||||
mRefCnt(0)
|
||||
{
|
||||
NS_PRECONDITION(aOriginPrincipal, "Must have an origin principal");
|
||||
|
||||
mString->AddRef();
|
||||
MOZ_COUNT_CTOR(nsCSSValue::URL);
|
||||
}
|
||||
|
||||
nsCSSValue::URL::~URL()
|
||||
{
|
||||
mString->Release();
|
||||
MOZ_COUNT_DTOR(nsCSSValue::URL);
|
||||
}
|
||||
|
||||
PRBool
|
||||
@ -485,8 +506,6 @@ nsCSSValue::Image::Image(nsIURI* aURI, nsStringBuffer* aString,
|
||||
nsIDocument* aDocument)
|
||||
: URL(aURI, aString, aReferrer, aOriginPrincipal)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsCSSValue::Image);
|
||||
|
||||
if (mURI &&
|
||||
nsContentUtils::CanLoadImage(mURI, aDocument, aDocument,
|
||||
aOriginPrincipal)) {
|
||||
@ -498,5 +517,38 @@ nsCSSValue::Image::Image(nsIURI* aURI, nsStringBuffer* aString,
|
||||
|
||||
nsCSSValue::Image::~Image()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsCSSValue::Image);
|
||||
}
|
||||
|
||||
nsCSSValueGradientStop::nsCSSValueGradientStop(const nsCSSValue& aLocation,
|
||||
const nsCSSValue& aColor)
|
||||
: mLocation(aLocation),
|
||||
mColor(aColor)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsCSSValueGradientStop);
|
||||
}
|
||||
|
||||
nsCSSValueGradientStop::nsCSSValueGradientStop(const nsCSSValueGradientStop& aOther)
|
||||
: mLocation(aOther.mLocation),
|
||||
mColor(aOther.mColor)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsCSSValueGradientStop);
|
||||
}
|
||||
|
||||
nsCSSValueGradientStop::~nsCSSValueGradientStop()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsCSSValueGradientStop);
|
||||
}
|
||||
|
||||
nsCSSValueGradient::nsCSSValueGradient(PRBool aIsRadial, const nsCSSValue& aStartX,
|
||||
const nsCSSValue& aStartY, const nsCSSValue& aStartRadius, const nsCSSValue& aEndX,
|
||||
const nsCSSValue& aEndY, const nsCSSValue& aEndRadius)
|
||||
: mIsRadial(aIsRadial),
|
||||
mStartX(aStartX),
|
||||
mStartY(aStartY),
|
||||
mEndX(aEndX),
|
||||
mEndY(aEndY),
|
||||
mStartRadius(aStartRadius),
|
||||
mEndRadius(aEndRadius),
|
||||
mRefCnt(0)
|
||||
{
|
||||
}
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCRTGlue.h"
|
||||
#include "nsStringBuffer.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class imgIRequest;
|
||||
class nsIDocument;
|
||||
@ -112,6 +113,7 @@ enum nsCSSUnit {
|
||||
|
||||
eCSSUnit_URL = 30, // (nsCSSValue::URL*) value
|
||||
eCSSUnit_Image = 31, // (nsCSSValue::Image*) value
|
||||
eCSSUnit_Gradient = 32, // (nsCSSValueGradient*) value
|
||||
eCSSUnit_Integer = 50, // (int) simple value
|
||||
eCSSUnit_Enumerated = 51, // (int) value has enumerated meaning
|
||||
eCSSUnit_EnumColor = 80, // (int) enumerated color (kColorKTable)
|
||||
@ -155,6 +157,8 @@ enum nsCSSUnit {
|
||||
eCSSUnit_Milliseconds = 3001 // (float) 1/1000 second
|
||||
};
|
||||
|
||||
struct nsCSSValueGradient;
|
||||
|
||||
class nsCSSValue {
|
||||
public:
|
||||
struct Array;
|
||||
@ -180,6 +184,7 @@ public:
|
||||
nsCSSValue(Array* aArray, nsCSSUnit aUnit) NS_HIDDEN;
|
||||
explicit nsCSSValue(URL* aValue) NS_HIDDEN;
|
||||
explicit nsCSSValue(Image* aValue) NS_HIDDEN;
|
||||
explicit nsCSSValue(nsCSSValueGradient* aValue) NS_HIDDEN;
|
||||
nsCSSValue(const nsCSSValue& aCopy) NS_HIDDEN;
|
||||
~nsCSSValue() { Reset(); }
|
||||
|
||||
@ -266,6 +271,12 @@ public:
|
||||
mValue.mURL->mURI : mValue.mImage->mURI;
|
||||
}
|
||||
|
||||
nsCSSValueGradient* GetGradientValue() const
|
||||
{
|
||||
NS_ASSERTION(mUnit == eCSSUnit_Gradient, "not a gradient value");
|
||||
return mValue.mGradient;
|
||||
}
|
||||
|
||||
URL* GetURLStructValue() const
|
||||
{
|
||||
// Not allowing this for Image values, because if the caller takes
|
||||
@ -307,6 +318,7 @@ public:
|
||||
NS_HIDDEN_(void) SetArrayValue(nsCSSValue::Array* aArray, nsCSSUnit aUnit);
|
||||
NS_HIDDEN_(void) SetURLValue(nsCSSValue::URL* aURI);
|
||||
NS_HIDDEN_(void) SetImageValue(nsCSSValue::Image* aImage);
|
||||
NS_HIDDEN_(void) SetGradientValue(nsCSSValueGradient* aGradient);
|
||||
NS_HIDDEN_(void) SetAutoValue();
|
||||
NS_HIDDEN_(void) SetInheritValue();
|
||||
NS_HIDDEN_(void) SetInitialValue();
|
||||
@ -355,17 +367,24 @@ public:
|
||||
return;
|
||||
}
|
||||
++mRefCnt;
|
||||
NS_LOG_ADDREF(this, mRefCnt, "nsCSSValue::URL", sizeof(*this));
|
||||
}
|
||||
void Release() {
|
||||
if (mRefCnt == PR_UINT32_MAX) {
|
||||
NS_WARNING("refcount overflow, leaking nsCSSValue::URL");
|
||||
return;
|
||||
}
|
||||
if (--mRefCnt == 0)
|
||||
--mRefCnt;
|
||||
NS_LOG_RELEASE(this, mRefCnt, "nsCSSValue::URL");
|
||||
if (mRefCnt == 0)
|
||||
delete this;
|
||||
}
|
||||
protected:
|
||||
nsrefcnt mRefCnt;
|
||||
|
||||
// not to be implemented
|
||||
URL(const URL& aOther);
|
||||
URL& operator=(const URL& aOther);
|
||||
};
|
||||
|
||||
struct Image : public URL {
|
||||
@ -381,13 +400,25 @@ public:
|
||||
|
||||
nsCOMPtr<imgIRequest> mRequest; // null == image load blocked or somehow failed
|
||||
|
||||
// Override Release so we delete correctly without a virtual destructor
|
||||
// Override AddRef and Release to not only log ourselves correctly, but
|
||||
// also so that we delete correctly without a virtual destructor
|
||||
void AddRef() {
|
||||
if (mRefCnt == PR_UINT32_MAX) {
|
||||
NS_WARNING("refcount overflow, leaking nsCSSValue::Image");
|
||||
return;
|
||||
}
|
||||
++mRefCnt;
|
||||
NS_LOG_ADDREF(this, mRefCnt, "nsCSSValue::Image", sizeof(*this));
|
||||
}
|
||||
|
||||
void Release() {
|
||||
if (mRefCnt == PR_UINT32_MAX) {
|
||||
NS_WARNING("refcount overflow, leaking nsCSSValue::Image");
|
||||
return;
|
||||
}
|
||||
if (--mRefCnt == 0)
|
||||
--mRefCnt;
|
||||
NS_LOG_RELEASE(this, mRefCnt, "nsCSSValue::Image");
|
||||
if (mRefCnt == 0)
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
@ -409,9 +440,105 @@ protected:
|
||||
Array* mArray;
|
||||
URL* mURL;
|
||||
Image* mImage;
|
||||
nsCSSValueGradient* mGradient;
|
||||
} mValue;
|
||||
};
|
||||
|
||||
struct nsCSSValueGradientStop {
|
||||
public:
|
||||
nsCSSValueGradientStop(const nsCSSValue& aLocation, const nsCSSValue& aColor) NS_HIDDEN;
|
||||
// needed to keep bloat logs happy when we use the nsTArray in nsCSSValueGradient
|
||||
nsCSSValueGradientStop(const nsCSSValueGradientStop& aOther) NS_HIDDEN;
|
||||
~nsCSSValueGradientStop() NS_HIDDEN;
|
||||
|
||||
nsCSSValue mLocation;
|
||||
nsCSSValue mColor;
|
||||
|
||||
PRBool operator==(const nsCSSValueGradientStop& aOther) const
|
||||
{
|
||||
return (mLocation == aOther.mLocation &&
|
||||
mColor == aOther.mColor);
|
||||
}
|
||||
|
||||
PRBool operator!=(const nsCSSValueGradientStop& aOther) const
|
||||
{
|
||||
return !(*this == aOther);
|
||||
}
|
||||
};
|
||||
|
||||
struct nsCSSValueGradient {
|
||||
nsCSSValueGradient(PRBool aIsRadial, const nsCSSValue& aStartX, const nsCSSValue& aStartY,
|
||||
const nsCSSValue& aStartRadius, const nsCSSValue& aEndX, const nsCSSValue& aEndY,
|
||||
const nsCSSValue& aEndRadius) NS_HIDDEN;
|
||||
|
||||
// true if gradient is radial, false if it is linear
|
||||
PRPackedBool mIsRadial;
|
||||
nsCSSValue mStartX;
|
||||
nsCSSValue mStartY;
|
||||
|
||||
nsCSSValue mEndX;
|
||||
nsCSSValue mEndY;
|
||||
|
||||
// Only meaningful if mIsRadial is true
|
||||
nsCSSValue mStartRadius;
|
||||
nsCSSValue mEndRadius;
|
||||
|
||||
nsTArray<nsCSSValueGradientStop> mStops;
|
||||
|
||||
PRBool operator==(const nsCSSValueGradient& aOther) const
|
||||
{
|
||||
if (mIsRadial != aOther.mIsRadial ||
|
||||
mStartX != aOther.mStartX ||
|
||||
mStartY != aOther.mStartY ||
|
||||
mStartRadius != aOther.mStartRadius ||
|
||||
mEndX != aOther.mEndX ||
|
||||
mEndY != aOther.mEndY ||
|
||||
mEndRadius != aOther.mEndRadius)
|
||||
return PR_FALSE;
|
||||
|
||||
if (mStops.Length() != aOther.mStops.Length())
|
||||
return PR_FALSE;
|
||||
|
||||
for (PRUint32 i = 0; i < mStops.Length(); i++) {
|
||||
if (mStops[i] != aOther.mStops[i])
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool operator!=(const nsCSSValueGradient& aOther) const
|
||||
{
|
||||
return !(*this == aOther);
|
||||
}
|
||||
|
||||
void AddRef() {
|
||||
if (mRefCnt == PR_UINT32_MAX) {
|
||||
NS_WARNING("refcount overflow, leaking nsCSSValue::Gradient");
|
||||
return;
|
||||
}
|
||||
++mRefCnt;
|
||||
NS_LOG_ADDREF(this, mRefCnt, "nsCSSValue::Gradient", sizeof(*this));
|
||||
}
|
||||
void Release() {
|
||||
if (mRefCnt == PR_UINT32_MAX) {
|
||||
NS_WARNING("refcount overflow, leaking nsCSSValue::Gradient");
|
||||
return;
|
||||
}
|
||||
--mRefCnt;
|
||||
NS_LOG_RELEASE(this, mRefCnt, "nsCSSValue::Gradient");
|
||||
if (mRefCnt == 0)
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
nsrefcnt mRefCnt;
|
||||
|
||||
// not to be implemented
|
||||
nsCSSValueGradient(const nsCSSValueGradient& aOther);
|
||||
nsCSSValueGradient& operator=(const nsCSSValueGradient& aOther);
|
||||
};
|
||||
|
||||
struct nsCSSValue::Array {
|
||||
|
||||
// return |Array| with reference count of zero
|
||||
@ -508,7 +635,9 @@ private:
|
||||
#undef CSSVALUE_LIST_FOR_EXTRA_VALUES
|
||||
|
||||
private:
|
||||
Array(const Array& aOther); // not to be implemented
|
||||
// not to be implemented
|
||||
Array(const Array& aOther);
|
||||
Array& operator=(const Array& aOther);
|
||||
};
|
||||
|
||||
#endif /* nsCSSValue_h___ */
|
||||
|
@ -1250,6 +1250,97 @@ nsComputedDOMStyle::GetBackgroundColor(nsIDOMCSSValue** aValue)
|
||||
return CallQueryInterface(val, aValue);
|
||||
}
|
||||
|
||||
static void
|
||||
AppendCSSGradientLength(const nsStyleCoord& aValue,
|
||||
nsROCSSPrimitiveValue* aPrimitive,
|
||||
nsAString& aString)
|
||||
{
|
||||
nsAutoString tokenString;
|
||||
if (aValue.GetUnit() == eStyleUnit_Coord)
|
||||
aPrimitive->SetAppUnits(aValue.GetCoordValue());
|
||||
else
|
||||
aPrimitive->SetPercent(aValue.GetPercentValue());
|
||||
aPrimitive->GetCssText(tokenString);
|
||||
aString.Append(tokenString);
|
||||
}
|
||||
|
||||
static void
|
||||
AppendCSSGradientRadius(const nscoord aValue,
|
||||
nsROCSSPrimitiveValue* aPrimitive,
|
||||
nsAString& aString)
|
||||
{
|
||||
nsAutoString tokenString;
|
||||
aPrimitive->SetAppUnits(aValue);
|
||||
aPrimitive->GetCssText(tokenString);
|
||||
aString.Append(tokenString);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComputedDOMStyle::GetCSSGradientString(const nsStyleGradient* aGradient,
|
||||
nsAString& aString)
|
||||
{
|
||||
if (aGradient->mIsRadial)
|
||||
aString.AssignLiteral("-moz-radial-gradient(");
|
||||
else
|
||||
aString.AssignLiteral("-moz-linear-gradient(");
|
||||
|
||||
nsROCSSPrimitiveValue *tmpVal = GetROCSSPrimitiveValue();
|
||||
if (!tmpVal)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// starting X position
|
||||
AppendCSSGradientLength(aGradient->mStartX, tmpVal, aString);
|
||||
aString.AppendLiteral(" ");
|
||||
|
||||
// starting Y position
|
||||
AppendCSSGradientLength(aGradient->mStartY, tmpVal, aString);
|
||||
aString.AppendLiteral(", ");
|
||||
|
||||
// starting radius
|
||||
if (aGradient->mIsRadial) {
|
||||
AppendCSSGradientRadius(aGradient->mStartRadius, tmpVal, aString);
|
||||
aString.AppendLiteral(", ");
|
||||
}
|
||||
|
||||
// ending X position
|
||||
AppendCSSGradientLength(aGradient->mEndX, tmpVal, aString);
|
||||
aString.AppendLiteral(" ");
|
||||
|
||||
// ending Y position
|
||||
AppendCSSGradientLength(aGradient->mEndY, tmpVal, aString);
|
||||
|
||||
// ending radius
|
||||
if (aGradient->mIsRadial) {
|
||||
aString.AppendLiteral(", ");
|
||||
AppendCSSGradientRadius(aGradient->mStartRadius, tmpVal, aString);
|
||||
}
|
||||
|
||||
// color stops
|
||||
for (PRUint32 i = 0; i < aGradient->mStops.Length(); ++i) {
|
||||
nsAutoString tokenString;
|
||||
aString.AppendLiteral(", color-stop(");
|
||||
|
||||
tmpVal->SetPercent(aGradient->mStops[i].mPosition);
|
||||
tmpVal->GetCssText(tokenString);
|
||||
aString.Append(tokenString);
|
||||
aString.AppendLiteral(", ");
|
||||
|
||||
nsresult rv = SetToRGBAColor(tmpVal, aGradient->mStops[i].mColor);
|
||||
if (NS_FAILED(rv)) {
|
||||
delete tmpVal;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
tmpVal->GetCssText(tokenString);
|
||||
aString.Append(tokenString);
|
||||
aString.AppendLiteral(")");
|
||||
}
|
||||
|
||||
delete tmpVal;
|
||||
aString.AppendLiteral(")");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComputedDOMStyle::GetBackgroundImage(nsIDOMCSSValue** aValue)
|
||||
{
|
||||
@ -1266,13 +1357,27 @@ nsComputedDOMStyle::GetBackgroundImage(nsIDOMCSSValue** aValue)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
imgIRequest *image = bg->mLayers[i].mImage;
|
||||
if (!image) {
|
||||
val->SetIdent(eCSSKeyword_none);
|
||||
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 {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
image->GetURI(getter_AddRefs(uri));
|
||||
val->SetURI(uri);
|
||||
val->SetIdent(eCSSKeyword_none);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,6 +131,9 @@ private:
|
||||
const PRInt32 aTable[],
|
||||
nsIDOMCSSValue** aResult);
|
||||
|
||||
nsresult GetCSSGradientString(const nsStyleGradient* aGradient,
|
||||
nsAString& aString);
|
||||
|
||||
/* Properties Queryable as CSSValues */
|
||||
|
||||
nsresult GetAppearance(nsIDOMCSSValue** aValue);
|
||||
|
@ -471,6 +471,81 @@ static PRBool SetColor(const nsCSSValue& aValue, const nscolor aParentColor,
|
||||
return result;
|
||||
}
|
||||
|
||||
static void SetGradientCoord(const nsCSSValue& aValue, nsPresContext* aPresContext,
|
||||
nsStyleContext* aContext, nsStyleCoord& aResult,
|
||||
PRBool& aCanStoreInRuleTree)
|
||||
{
|
||||
// If coordinate is an enumerated type, handle it explicitly.
|
||||
if (aValue.GetUnit() == eCSSUnit_Enumerated) {
|
||||
aResult.SetPercentValue(GetFloatFromBoxPosition(aValue.GetIntValue()));
|
||||
return;
|
||||
}
|
||||
|
||||
// OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
|
||||
PRBool result = SetCoord(aValue, aResult, nsStyleCoord(), SETCOORD_LP,
|
||||
aContext, aPresContext, aCanStoreInRuleTree);
|
||||
NS_ABORT_IF_FALSE(result, "Incorrect data structure created by parsing code");
|
||||
}
|
||||
|
||||
static void SetGradient(const nsCSSValue& aValue, nsPresContext* aPresContext,
|
||||
nsStyleContext* aContext, nsStyleGradient& aResult,
|
||||
PRBool& aCanStoreInRuleTree)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Gradient,
|
||||
"The given data is not a gradient");
|
||||
|
||||
nsCSSValueGradient* gradient = aValue.GetGradientValue();
|
||||
aResult.mIsRadial = gradient->mIsRadial;
|
||||
|
||||
// start values
|
||||
SetGradientCoord(gradient->mStartX, aPresContext, aContext,
|
||||
aResult.mStartX, aCanStoreInRuleTree);
|
||||
|
||||
SetGradientCoord(gradient->mStartY, aPresContext, aContext,
|
||||
aResult.mStartY, aCanStoreInRuleTree);
|
||||
|
||||
if (gradient->mIsRadial) {
|
||||
NS_ABORT_IF_FALSE(gradient->mStartRadius.IsLengthUnit(),
|
||||
"Incorrect data structure created by parsing code");
|
||||
aResult.mStartRadius = CalcLength(gradient->mStartRadius, aContext,
|
||||
aPresContext, aCanStoreInRuleTree);
|
||||
}
|
||||
|
||||
// end values
|
||||
SetGradientCoord(gradient->mEndX, aPresContext, aContext,
|
||||
aResult.mEndX, aCanStoreInRuleTree);
|
||||
|
||||
SetGradientCoord(gradient->mEndY, aPresContext, aContext,
|
||||
aResult.mEndY, aCanStoreInRuleTree);
|
||||
|
||||
if (gradient->mIsRadial) {
|
||||
NS_ABORT_IF_FALSE(gradient->mEndRadius.IsLengthUnit(),
|
||||
"Incorrect data structure created by parsing code");
|
||||
aResult.mEndRadius = CalcLength(gradient->mEndRadius, aContext,
|
||||
aPresContext, aCanStoreInRuleTree);
|
||||
}
|
||||
|
||||
// stops
|
||||
for (PRUint32 i = 0; i < gradient->mStops.Length(); i++) {
|
||||
nsStyleGradientStop stop;
|
||||
nsCSSValueGradientStop &valueStop = gradient->mStops[i];
|
||||
|
||||
if (valueStop.mLocation.GetUnit() == eCSSUnit_Percent)
|
||||
stop.mPosition = valueStop.mLocation.GetPercentValue();
|
||||
else
|
||||
stop.mPosition = valueStop.mLocation.GetFloatValue();
|
||||
|
||||
// inherit is not a valid color for stops, so we pass in a dummy
|
||||
// parent color
|
||||
NS_ASSERTION(valueStop.mColor.GetUnit() != eCSSUnit_Inherit,
|
||||
"inherit is not a valid color for gradient stops");
|
||||
SetColor(valueStop.mColor, NS_RGB(0, 0, 0), aPresContext,
|
||||
aContext, stop.mColor, aCanStoreInRuleTree);
|
||||
|
||||
aResult.mStops.AppendElement(stop);
|
||||
}
|
||||
}
|
||||
|
||||
// flags for SetDiscrete - align values with SETCOORD_* constants
|
||||
// where possible
|
||||
|
||||
@ -3803,20 +3878,30 @@ struct BackgroundItemComputer<nsCSSValueList, PRUint8>
|
||||
};
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
struct BackgroundItemComputer<nsCSSValueList, nsCOMPtr<imgIRequest> >
|
||||
struct BackgroundItemComputer<nsCSSValueList, nsStyleBackground::Image>
|
||||
{
|
||||
static void ComputeValue(nsStyleContext* aStyleContext,
|
||||
const nsCSSValueList* aSpecifiedValue,
|
||||
nsCOMPtr<imgIRequest>& aComputedValue,
|
||||
nsStyleBackground::Image& aComputedValue,
|
||||
PRBool& aCanStoreInRuleTree)
|
||||
{
|
||||
const nsCSSValue &value = aSpecifiedValue->mValue;
|
||||
if (eCSSUnit_Image == value.GetUnit()) {
|
||||
aComputedValue = value.GetImageValue();
|
||||
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 = nsnull;
|
||||
aComputedValue.SetNull();
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -4056,10 +4141,11 @@ nsRuleNode::ComputeBackgroundData(void* aStartStruct,
|
||||
PRBool rebuild = PR_FALSE;
|
||||
|
||||
// background-image: url (stored as image), none, inherit [list]
|
||||
nsStyleBackground::Image initialImage;
|
||||
SetBackgroundList(aContext, colorData.mBackImage, bg->mLayers,
|
||||
parentBG->mLayers, &nsStyleBackground::Layer::mImage,
|
||||
nsCOMPtr<imgIRequest>(nsnull), parentBG->mImageCount,
|
||||
bg->mImageCount, maxItemCount, rebuild, canStoreInRuleTree);
|
||||
initialImage, parentBG->mImageCount, bg->mImageCount,
|
||||
maxItemCount, rebuild, canStoreInRuleTree);
|
||||
|
||||
// background-repeat: enum, inherit, initial [list]
|
||||
SetBackgroundList(aContext, colorData.mBackRepeat, bg->mLayers,
|
||||
|
@ -1206,6 +1206,51 @@ nsChangeHint nsStyleColor::MaxDifference()
|
||||
}
|
||||
#endif
|
||||
|
||||
// --------------------
|
||||
// nsStyleGradient
|
||||
//
|
||||
PRBool
|
||||
nsStyleGradient::operator==(const nsStyleGradient& aOther) const
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mIsRadial || (mStartRadius == 0 && mEndRadius == 0),
|
||||
"incorrect unused radius values");
|
||||
NS_ABORT_IF_FALSE(aOther.mIsRadial ||
|
||||
(aOther.mStartRadius == 0 && aOther.mEndRadius == 0),
|
||||
"incorrect unused radius values");
|
||||
|
||||
if (mIsRadial != aOther.mIsRadial ||
|
||||
mStartX != aOther.mStartX ||
|
||||
mStartY != aOther.mStartY ||
|
||||
mStartRadius != aOther.mStartRadius ||
|
||||
mEndX != aOther.mEndX ||
|
||||
mEndY != aOther.mEndY ||
|
||||
mEndRadius != aOther.mEndRadius)
|
||||
return PR_FALSE;
|
||||
|
||||
if (mStops.Length() != aOther.mStops.Length())
|
||||
return PR_FALSE;
|
||||
|
||||
for (PRUint32 i = 0; i < mStops.Length(); i++) {
|
||||
if (mStops[i].mPosition != aOther.mStops[i].mPosition ||
|
||||
mStops[i].mColor != aOther.mStops[i].mColor)
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsStyleGradient::nsStyleGradient(void)
|
||||
: mIsRadial(PR_FALSE)
|
||||
, mStartRadius(0)
|
||||
, mEndRadius(0)
|
||||
, mRefCnt(0)
|
||||
{
|
||||
mStartX.SetCoordValue(0);
|
||||
mStartY.SetCoordValue(0);
|
||||
mEndX.SetCoordValue(0);
|
||||
mEndY.SetCoordValue(0);
|
||||
}
|
||||
|
||||
// --------------------
|
||||
// nsStyleBackground
|
||||
//
|
||||
@ -1284,7 +1329,8 @@ 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) {
|
||||
if (layer.mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
|
||||
layer.mImage.GetType() != eBackgroundImage_Null) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
@ -1293,7 +1339,8 @@ PRBool nsStyleBackground::HasFixedBackground() const
|
||||
|
||||
PRBool nsStyleBackground::IsTransparent() const
|
||||
{
|
||||
return !BottomLayer().mImage && mImageCount == 1 &&
|
||||
return BottomLayer().mImage.GetType() == eBackgroundImage_Null &&
|
||||
mImageCount == 1 &&
|
||||
NS_GET_A(mBackgroundColor) == 0;
|
||||
}
|
||||
|
||||
@ -1363,7 +1410,7 @@ nsStyleBackground::Layer::SetInitialValues()
|
||||
mRepeat = NS_STYLE_BG_REPEAT_XY;
|
||||
mPosition.SetInitialValues();
|
||||
mSize.SetInitialValues();
|
||||
mImage = nsnull;
|
||||
mImage.SetNull();
|
||||
}
|
||||
|
||||
PRBool nsStyleBackground::Layer::operator==(const Layer& aOther) const
|
||||
@ -1374,7 +1421,99 @@ PRBool nsStyleBackground::Layer::operator==(const Layer& aOther) const
|
||||
mRepeat == aOther.mRepeat &&
|
||||
mPosition == aOther.mPosition &&
|
||||
mSize == aOther.mSize &&
|
||||
EqualImages(mImage, aOther.mImage);
|
||||
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);
|
||||
DoCopy(aOther);
|
||||
}
|
||||
|
||||
nsStyleBackground::Image&
|
||||
nsStyleBackground::Image::operator=(const nsStyleBackground::Image& aOther)
|
||||
{
|
||||
DoCopy(aOther);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void nsStyleBackground::Image::DoCopy(const nsStyleBackground::Image& aOther)
|
||||
{
|
||||
if (this == &aOther)
|
||||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// --------------------
|
||||
|
@ -124,6 +124,68 @@ struct nsStyleFont {
|
||||
#endif
|
||||
};
|
||||
|
||||
struct nsStyleGradientStop {
|
||||
nscolor mColor;
|
||||
float mPosition; // 0.0 - 1.0
|
||||
};
|
||||
|
||||
class nsStyleGradient {
|
||||
public:
|
||||
nsStyleGradient();
|
||||
|
||||
PRPackedBool mIsRadial;
|
||||
|
||||
nsStyleCoord mStartX; // percent or coord
|
||||
nsStyleCoord mStartY; // percent or coord
|
||||
|
||||
nsStyleCoord mEndX; // percent or coord
|
||||
nsStyleCoord mEndY; // percent or coord
|
||||
|
||||
nscoord mStartRadius;
|
||||
nscoord mEndRadius;
|
||||
|
||||
// stops are in the order specified in the stylesheet
|
||||
nsTArray<nsStyleGradientStop> mStops;
|
||||
|
||||
nsrefcnt AddRef() {
|
||||
if (mRefCnt == PR_UINT32_MAX) {
|
||||
NS_WARNING("refcount overflow, leaking nsStyleGradient");
|
||||
return mRefCnt;
|
||||
}
|
||||
++mRefCnt;
|
||||
NS_LOG_ADDREF(this, mRefCnt, "nsStyleGradient", sizeof(*this));
|
||||
return mRefCnt;
|
||||
}
|
||||
|
||||
nsrefcnt Release() {
|
||||
if (mRefCnt == PR_UINT32_MAX) {
|
||||
NS_WARNING("refcount overflow, leaking nsStyleGradient");
|
||||
return mRefCnt;
|
||||
}
|
||||
--mRefCnt;
|
||||
NS_LOG_RELEASE(this, mRefCnt, "nsStyleGradient");
|
||||
if (mRefCnt == 0) {
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return mRefCnt;
|
||||
}
|
||||
|
||||
PRBool operator==(const nsStyleGradient& aOther) const;
|
||||
PRBool operator!=(const nsStyleGradient& aOther) const {
|
||||
return !(*this == aOther);
|
||||
};
|
||||
|
||||
private:
|
||||
nsrefcnt mRefCnt;
|
||||
|
||||
~nsStyleGradient() {}
|
||||
|
||||
// Not to be implemented
|
||||
nsStyleGradient(const nsStyleGradient& aOther);
|
||||
nsStyleGradient& operator=(const nsStyleGradient& aOther);
|
||||
};
|
||||
|
||||
struct nsStyleColor {
|
||||
nsStyleColor(nsPresContext* aPresContext);
|
||||
nsStyleColor(const nsStyleColor& aOther);
|
||||
@ -147,6 +209,12 @@ struct nsStyleColor {
|
||||
nscolor mColor; // [inherited]
|
||||
};
|
||||
|
||||
enum nsStyleBackgroundImageType {
|
||||
eBackgroundImage_Null,
|
||||
eBackgroundImage_Image,
|
||||
eBackgroundImage_Gradient
|
||||
};
|
||||
|
||||
struct nsStyleBackground {
|
||||
nsStyleBackground();
|
||||
nsStyleBackground(const nsStyleBackground& aOther);
|
||||
@ -228,6 +296,46 @@ 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 {
|
||||
@ -236,7 +344,7 @@ struct nsStyleBackground {
|
||||
PRUint8 mOrigin; // [reset] See nsStyleConsts.h
|
||||
PRUint8 mRepeat; // [reset] See nsStyleConsts.h
|
||||
Position mPosition; // [reset]
|
||||
nsCOMPtr<imgIRequest> mImage; // [reset]
|
||||
Image mImage; // [reset]
|
||||
Size mSize; // [reset]
|
||||
|
||||
// Initializes only mImage
|
||||
|
@ -625,7 +625,7 @@ var gCSSProperties = {
|
||||
initial_values: [ "transparent", "none", "repeat", "scroll", "0% 0%", "top left", "left top", "transparent none", "top left none", "left top none", "none left top", "none top left", "none 0% 0%", "transparent none repeat scroll top left", "left top repeat none scroll transparent" ],
|
||||
other_values: [
|
||||
/* without multiple backgrounds */
|
||||
"green", "none green repeat scroll left top", "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==)", "repeat url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==') transparent left top scroll", "repeat-x", "repeat-y", "no-repeat", "none repeat-y transparent scroll 0% 0%", "fixed", "0% top transparent fixed repeat none", "top", "left", "50% 50%", "center", "bottom right scroll none transparent repeat", "50% transparent", "transparent 50%", "50%",
|
||||
"green", "none green repeat scroll left top", "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==)", "repeat url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==') transparent left top scroll", "repeat-x", "repeat-y", "no-repeat", "none repeat-y transparent scroll 0% 0%", "fixed", "0% top transparent fixed repeat none", "top", "left", "50% 50%", "center", "bottom right scroll none transparent repeat", "50% transparent", "transparent 50%", "50%", "-moz-radial-gradient(10% bottom, 30px, 20px 20px, 10px, from(#ffffff), to(black)) scroll no-repeat", "-moz-linear-gradient(10px 10px, 20px 20px, from(red), to(blue)) repeat",
|
||||
/* multiple backgrounds */
|
||||
"url(404.png), url(404.png)",
|
||||
"url(404.png), url(404.png) transparent",
|
||||
@ -633,6 +633,7 @@ var gCSSProperties = {
|
||||
"repeat-x, fixed, none",
|
||||
"0% top url(404.png), url(404.png) 0% top",
|
||||
"fixed repeat-y top left url(404.png), repeat-x green",
|
||||
"url(404.png), -moz-linear-gradient(20px 20px, 30px 30px, from(blue), to(green)) black",
|
||||
/* test cases with clip+origin in the shorthand */
|
||||
// This is commented out for now until we change
|
||||
// -moz-background-clip to background-clip, -moz-background-origin
|
||||
@ -688,9 +689,30 @@ var gCSSProperties = {
|
||||
"none, none, none, none, none",
|
||||
"url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==), none",
|
||||
"none, url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==), none",
|
||||
"url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==), url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==)"
|
||||
"url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==), url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==)",
|
||||
|
||||
"-moz-radial-gradient(45px 60px, 10px, 52px 50px, 30px, from(red), color-stop(90%, #019f62), to(rgba(1, 159, 98, 0)))",
|
||||
"-moz-linear-gradient(20% center, left bottom, color-stop(0, #ffff00), to(green))",
|
||||
"-moz-radial-gradient(50% 50%, 60px, 10% 20%, 20px, to(red), from(pink), color-stop(0.94, goldenrod))",
|
||||
"-moz-linear-gradient(20px 10px, 100px top, from(rgb(10, 100, 0)), color-stop(1, rgba(10, 20, 30, 0.4)))",
|
||||
"-moz-radial-gradient(center top, 10px, right bottom, 20px, color-stop(0.7, green), color-stop(20%, #ccddee), from(rgb(1, 2, 3)), color-stop(0.95, #aa0012))",
|
||||
"-moz-linear-gradient(10px 20%, -50px -10%, from(green))",
|
||||
"-moz-linear-gradient(10px 10px, 20px 20px)",
|
||||
"-moz-linear-gradient(10px 10px, 20px 20px, color-stop(314%, blue))",
|
||||
"-moz-linear-gradient(10px 10px, 20px 20px, color-stop(-0.2, green))",
|
||||
"-moz-linear-gradient( 10px 10px , 40px 20px , from(blue) )"
|
||||
],
|
||||
invalid_values: []
|
||||
invalid_values: [ "-moz-linear-gradient(10px 10px, 20px, 30px 30px, 40px, from(blue), to(red))",
|
||||
"-moz-radial-gradient(20px 20px, 10px 10px, from(green), to(#ff00ff))",
|
||||
"-moz-radial-gradient(10px 10px, 20%, 40px 40px, 10px, from(green), to(#ff00ff))",
|
||||
"-moz-linear-gradient(10px, 20px, 30px, 40px, color-stop(0.5, #00ccff))",
|
||||
"-moz-linear-gradient(20px 20px, from(blue), to(red))",
|
||||
"-moz-linear-gradient(40px 40px, 10px 10px, from(blue) to(red) color-stop(10%, fuchsia))",
|
||||
"-moz-linear-gradient(20px 20px 30px, 10px 10px, from(red), to(#ff0000))",
|
||||
"-moz-radial-gradient(left top, center, 20px 20px, 10px, from(blue), to(red))",
|
||||
"-moz-linear-gradient(left left, top top, from(blue))",
|
||||
"-moz-linear-gradient(inherit, 10px 10px, from(blue))",
|
||||
"-moz-linear-gradient()" ]
|
||||
},
|
||||
"background-position": {
|
||||
domProp: "backgroundPosition",
|
||||
|
@ -202,7 +202,7 @@ TableBackgroundPainter::TableBackgroundData::ShouldSetBCBorder()
|
||||
}
|
||||
|
||||
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, mBackground) {
|
||||
if (mBackground->mLayers[i].mImage)
|
||||
if (mBackground->mLayers[i].mImage.GetType() != eBackgroundImage_Null)
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
|
@ -4118,7 +4118,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 ||
|
||||
if (background->BottomLayer().mImage.GetType() != eBackgroundImage_Null ||
|
||||
background->mImageCount > 1 ||
|
||||
NS_GET_A(background->mBackgroundColor) < 255 ||
|
||||
PR_ABS(delta)*mRowHeight >= mRect.height) {
|
||||
@ -4175,7 +4175,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 ||
|
||||
if (background->BottomLayer().mImage.GetType() != eBackgroundImage_Null ||
|
||||
background->mImageCount > 1 ||
|
||||
NS_GET_A(background->mBackgroundColor) < 255 ||
|
||||
PR_ABS(delta) >= mRect.width) {
|
||||
|
Loading…
Reference in New Issue
Block a user