Bug 189519 - Implement CSS3 (-moz- for now)background-size. r=dbaron, other useful review comments from roc/bz

This commit is contained in:
Jeff Walden 2009-05-28 11:09:05 -07:00
Родитель c02a6b6c3f
Коммит 1fb19be474
82 изменённых файлов: 2302 добавлений и 67 удалений

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

@ -39,7 +39,7 @@
#include "nsIDOMCSS2Properties.idl"
[scriptable, uuid(e7245a21-3f46-4e67-82bf-a9b326fe74ee)]
[scriptable, uuid(643f64d3-6b95-4d9a-ac75-c01a6f4c88cb)]
interface nsIDOMNSCSS2Properties : nsIDOMCSS2Properties
{
/* Non-DOM 2 extensions */
@ -256,5 +256,8 @@ interface nsIDOMNSCSS2Properties : nsIDOMCSS2Properties
attribute DOMString MozWindowShadow;
// raises(DOMException) on setting
attribute DOMString MozBackgroundSize;
// raises(DOMException) on setting
};

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

@ -88,12 +88,29 @@ inline void VERIFY_COORD(nscoord aCoord) {
#endif
}
inline nscoord NSCoordMultiply(nscoord aCoord, float aVal) {
/**
* Returns aCoord * aVal, capping the product to nscoord_MAX.
*
* Note: If/when we start using floats for nscoords, this function won't be
* necessary. Normal float multiplication correctly handles overflowing
* multiplications, automatically saturating to infinity.
*/
inline nscoord NSCoordSaturatingMultiply(nscoord aCoord, float aVal) {
VERIFY_COORD(aCoord);
NS_ABORT_IF_FALSE(aVal >= 0.0f,
"negative scaling factors must be handled manually");
#ifdef NS_COORD_IS_FLOAT
return floorf(aCoord*aVal);
return floorf(aCoord * aVal);
#else
return (PRInt32)(aCoord*aVal);
// This one's only a warning because it's possible to trigger
NS_WARN_IF_FALSE(aCoord > 0
? floorf(aCoord * aVal) < nscoord_MAX
: ceilf(aCoord * aVal) > nscoord_MIN,
"nscoord multiplication capped");
if (aCoord > 0)
return PRInt32(PR_MIN(nscoord_MAX, aCoord * aVal));
return PRInt32(PR_MAX(nscoord_MIN, aCoord * aVal));
#endif
}

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

@ -27,6 +27,7 @@
* L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
* Michael Ventnor <m.ventnor@gmail.com>
* Rob Arnold <robarnold@mozilla.com>
* Jeff Walden <jwalden+code@mit.edu>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -1395,8 +1396,12 @@ 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
UseImageRequestForBackground(imgIRequest *aRequest)
HaveCompleteBackgroundImage(imgIRequest *aRequest)
{
if (!aRequest)
return PR_FALSE;
@ -1496,37 +1501,37 @@ static nscolor
DetermineBackgroundColorInternal(nsPresContext* aPresContext,
const nsStyleBackground& aBackground,
nsIFrame* aFrame,
PRBool* aDrawBackgroundImage,
PRBool* aDrawBackgroundColor,
PRBool& aDrawBackgroundImage,
PRBool& aDrawBackgroundColor,
nsCOMPtr<imgIRequest>& aBottomImage)
{
*aDrawBackgroundImage = PR_TRUE;
*aDrawBackgroundColor = PR_TRUE;
aDrawBackgroundImage = PR_TRUE;
aDrawBackgroundColor = PR_TRUE;
if (aFrame->HonorPrintBackgroundSettings()) {
*aDrawBackgroundImage = aPresContext->GetBackgroundImageDraw();
*aDrawBackgroundColor = aPresContext->GetBackgroundColorDraw();
aDrawBackgroundImage = aPresContext->GetBackgroundImageDraw();
aDrawBackgroundColor = aPresContext->GetBackgroundColorDraw();
}
aBottomImage = aBackground.BottomLayer().mImage;
if (!aDrawBackgroundImage || !UseImageRequestForBackground(aBottomImage)) {
if (!aDrawBackgroundImage || !HaveCompleteBackgroundImage(aBottomImage)) {
aBottomImage = nsnull;
}
nscolor bgColor;
if (*aDrawBackgroundColor) {
if (aDrawBackgroundColor) {
bgColor = aBackground.mBackgroundColor;
if (NS_GET_A(bgColor) == 0)
*aDrawBackgroundColor = PR_FALSE;
aDrawBackgroundColor = PR_FALSE;
} else {
// If GetBackgroundColorDraw() is false, we are still expected to
// draw color in the background of any frame that's not completely
// transparent, but we are expected to use white instead of whatever
// color was specified.
bgColor = NS_RGB(255, 255, 255);
if (*aDrawBackgroundImage || !aBackground.IsTransparent())
*aDrawBackgroundColor = PR_TRUE;
if (aDrawBackgroundImage || !aBackground.IsTransparent())
aDrawBackgroundColor = PR_TRUE;
else
bgColor = NS_RGBA(0,0,0,0);
}
@ -1545,8 +1550,8 @@ nsCSSRendering::DetermineBackgroundColor(nsPresContext* aPresContext,
return DetermineBackgroundColorInternal(aPresContext,
aBackground,
aFrame,
&drawBackgroundImage,
&drawBackgroundColor,
drawBackgroundImage,
drawBackgroundColor,
bottomImage);
}
@ -1596,8 +1601,8 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
nscolor bgColor = DetermineBackgroundColorInternal(aPresContext,
aBackground,
aForFrame,
&drawBackgroundImage,
&drawBackgroundColor,
drawBackgroundImage,
drawBackgroundColor,
bottomImage);
// At this point, drawBackgroundImage and drawBackgroundColor are
@ -1628,7 +1633,7 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
// determined by the value of 'background-clip' in
// SetupCurrentBackgroundClip. (Arguably it should be the
// intersection, but that breaks the table painter -- in particular,
// taking the intersection breaks reftests/bugs/403429-1[ab].)
// taking the intersection breaks reftests/bugs/403249-1[ab].)
nsRect bgClipArea, dirtyRect;
gfxRect dirtyRectGfx;
PRUint8 currentBackgroundClip;
@ -1722,6 +1727,25 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
}
}
static inline float
ScaleDimension(nsStyleBackground::Size::Dimension aDimension,
PRUint8 aType,
nscoord aLength, nscoord aAvailLength)
{
switch (aType) {
case nsStyleBackground::Size::ePercentage:
return double(aDimension.mFloat) * (double(aAvailLength) / double(aLength));
case nsStyleBackground::Size::eLength:
return double(aDimension.mCoord) / double(aLength);
default:
NS_ABORT_IF_FALSE(PR_FALSE, "bad aDimension.mType");
return 1.0f;
case nsStyleBackground::Size::eAuto:
NS_ABORT_IF_FALSE(PR_FALSE, "aDimension.mType == eAuto isn't handled");
return 1.0f;
}
}
static void
PaintBackgroundLayer(nsPresContext* aPresContext,
nsIRenderingContext& aRenderingContext,
@ -1732,15 +1756,69 @@ PaintBackgroundLayer(nsPresContext* aPresContext,
const nsStyleBackground& aBackground,
const nsStyleBackground::Layer& aLayer)
{
/*
* The background properties we need to keep in mind when drawing background
* layers are:
*
* background-image
* background-repeat
* background-attachment
* background-position
* background-clip (-moz-background-clip)
* background-origin (-moz-background-origin)
* background-size (-moz-background-size)
* background-break (-moz-background-inline-policy)
*
* (background-color applies to the entire element and not to individual
* layers, so it is irrelevant to this method.)
*
* These properties have the following dependencies upon each other when
* determining rendering:
*
* background-image
* no dependencies
* background-repeat
* no dependencies
* background-attachment
* no dependencies
* background-position
* depends upon background-size (for the image's scaled size) and
* background-break (for the background positioning area)
* background-clip
* no dependencies
* background-origin
* depends upon background-attachment (only in the case where that value
* is 'fixed')
* background-size
* depends upon background-break (for the background positioning area for
* resolving percentages), background-image (for the image's intrinsic
* size), background-repeat (if that value is 'round'), and
* background-origin (for the background painting area, when
* background-repeat is 'round')
* background-break
* depends upon background-origin (specifying how the boxes making up the
* background positioning area are determined)
*
* As a result of only-if dependencies we don't strictly do a topological
* sort of the above properties when processing, but it's pretty close to one:
*
* background-clip (by caller)
* background-image
* background-break, background-origin
* background-attachment (postfix for background-{origin,break} if 'fixed')
* background-size
* background-position
* background-repeat
*/
// Lookup the image
imgIRequest *req = aLayer.mImage;
if (!UseImageRequestForBackground(req)) {
// There's no image or it's not ready to be painted.
if (!HaveCompleteBackgroundImage(req))
return;
}
nsCOMPtr<imgIContainer> image;
req->GetImage(getter_AddRefs(image));
req = nsnull;
nsIntSize imageIntSize;
image->GetWidth(&imageIntSize.width);
@ -1750,27 +1828,33 @@ PaintBackgroundLayer(nsPresContext* aPresContext,
imageSize.width = nsPresContext::CSSPixelsToAppUnits(imageIntSize.width);
imageSize.height = nsPresContext::CSSPixelsToAppUnits(imageIntSize.height);
req = nsnull;
if (imageSize.width == 0 || imageSize.height == 0)
return;
// relative to aBorderArea
nsRect bgOriginRect(0, 0, 0, 0);
nsRect bgPositioningArea(0, 0, 0, 0);
nsIAtom* frameType = aForFrame->GetType();
nsIFrame* geometryFrame = aForFrame;
if (frameType == nsGkAtoms::inlineFrame ||
frameType == nsGkAtoms::positionedInlineFrame) {
// XXXjwalden Strictly speaking this is not quite faithful to how
// background-break is supposed to interact with background-origin values,
// but it's a non-trivial amount of work to make it fully conformant, and
// until the specification is more finalized (and assuming background-break
// even makes the cut) it doesn't make sense to hammer out exact behavior.
switch (aBackground.mBackgroundInlinePolicy) {
case NS_STYLE_BG_INLINE_POLICY_EACH_BOX:
bgOriginRect = nsRect(nsPoint(0,0), aBorderArea.Size());
bgPositioningArea = nsRect(nsPoint(0,0), aBorderArea.Size());
break;
case NS_STYLE_BG_INLINE_POLICY_BOUNDING_BOX:
bgOriginRect = gInlineBGData->GetBoundingRect(aForFrame);
bgPositioningArea = gInlineBGData->GetBoundingRect(aForFrame);
break;
default:
NS_ERROR("Unknown background-inline-policy value! "
"Please, teach me what to do.");
case NS_STYLE_BG_INLINE_POLICY_CONTINUOUS:
bgOriginRect = gInlineBGData->GetContinuousRect(aForFrame);
bgPositioningArea = gInlineBGData->GetContinuousRect(aForFrame);
break;
}
} else if (frameType == nsGkAtoms::canvasFrame) {
@ -1780,10 +1864,10 @@ PaintBackgroundLayer(nsPresContext* aPresContext,
// finished and this page only displays the continuations of
// absolutely positioned content).
if (geometryFrame) {
bgOriginRect = geometryFrame->GetRect();
bgPositioningArea = geometryFrame->GetRect();
}
} else {
bgOriginRect = nsRect(nsPoint(0,0), aBorderArea.Size());
bgPositioningArea = nsRect(nsPoint(0,0), aBorderArea.Size());
}
// Background images are tiled over the 'background-clip' area
@ -1791,11 +1875,11 @@ PaintBackgroundLayer(nsPresContext* aPresContext,
if (aLayer.mOrigin != NS_STYLE_BG_ORIGIN_BORDER && geometryFrame) {
nsMargin border = geometryFrame->GetUsedBorder();
geometryFrame->ApplySkipSides(border);
bgOriginRect.Deflate(border);
bgPositioningArea.Deflate(border);
if (aLayer.mOrigin != NS_STYLE_BG_ORIGIN_PADDING) {
nsMargin padding = geometryFrame->GetUsedPadding();
geometryFrame->ApplySkipSides(padding);
bgOriginRect.Deflate(padding);
bgPositioningArea.Deflate(padding);
NS_ASSERTION(aLayer.mOrigin == NS_STYLE_BG_ORIGIN_CONTENT,
"unknown background-origin value");
}
@ -1805,7 +1889,7 @@ PaintBackgroundLayer(nsPresContext* aPresContext,
//
// relative to aBorderArea.TopLeft() (which is where the top-left
// of aForFrame's border-box will be rendered)
nsPoint imageTopLeft, anchor;
nsPoint imageTopLeft, anchor, offset;
if (NS_STYLE_BG_ATTACHMENT_FIXED == aLayer.mAttachment) {
// If it's a fixed background attachment, then the image is placed
// relative to the viewport, which is the area of the root frame
@ -1827,7 +1911,8 @@ PaintBackgroundLayer(nsPresContext* aPresContext,
// else this is an embedded shell and its root frame is what we want
}
nsRect viewportArea(nsPoint(0, 0), topFrame->GetSize());
// Set the background positioning area to the viewport's area.
bgPositioningArea.SetRect(nsPoint(0, 0), topFrame->GetSize());
if (!pageContentFrame) {
// Subtract the size of scrollbars.
@ -1835,29 +1920,70 @@ PaintBackgroundLayer(nsPresContext* aPresContext,
aPresContext->PresShell()->GetRootScrollFrameAsScrollable();
if (scrollableFrame) {
nsMargin scrollbars = scrollableFrame->GetActualScrollbarSizes();
viewportArea.Deflate(scrollbars);
bgPositioningArea.Deflate(scrollbars);
}
}
// Get the anchor point, relative to the viewport.
ComputeBackgroundAnchorPoint(aLayer, viewportArea.Size(), imageSize,
&imageTopLeft, &anchor);
// Convert the anchor point from viewport coordinates to aForFrame
// coordinates.
nsPoint offset = viewportArea.TopLeft() - aForFrame->GetOffsetTo(topFrame);
imageTopLeft += offset;
anchor += offset;
offset = bgPositioningArea.TopLeft() - aForFrame->GetOffsetTo(topFrame);
} else {
ComputeBackgroundAnchorPoint(aLayer, bgOriginRect.Size(), imageSize,
&imageTopLeft, &anchor);
imageTopLeft += bgOriginRect.TopLeft();
anchor += bgOriginRect.TopLeft();
offset = bgPositioningArea.TopLeft();
}
// Scale the image as specified for background-size and as required for
// proper background positioning when background-position is defined with
// percentages.
float scaleX, scaleY;
switch (aLayer.mSize.mWidthType) {
case nsStyleBackground::Size::eContain:
case nsStyleBackground::Size::eCover: {
float scaleFitX = double(bgPositioningArea.width) / imageSize.width;
float scaleFitY = double(bgPositioningArea.height) / imageSize.height;
if (aLayer.mSize.mWidthType == nsStyleBackground::Size::eCover) {
scaleX = scaleY = PR_MAX(scaleFitX, scaleFitY);
} else {
scaleX = scaleY = PR_MIN(scaleFitX, scaleFitY);
}
break;
}
default: {
if (aLayer.mSize.mWidthType == nsStyleBackground::Size::eAuto) {
if (aLayer.mSize.mHeightType == nsStyleBackground::Size::eAuto) {
scaleX = scaleY = 1.0f;
} else {
scaleX = scaleY =
ScaleDimension(aLayer.mSize.mHeight, aLayer.mSize.mHeightType,
imageSize.height, bgPositioningArea.height);
}
} else {
if (aLayer.mSize.mHeightType == nsStyleBackground::Size::eAuto) {
scaleX = scaleY =
ScaleDimension(aLayer.mSize.mWidth, aLayer.mSize.mWidthType,
imageSize.width, bgPositioningArea.width);
} else {
scaleX = ScaleDimension(aLayer.mSize.mWidth, aLayer.mSize.mWidthType,
imageSize.width, bgPositioningArea.width);
scaleY = ScaleDimension(aLayer.mSize.mHeight, aLayer.mSize.mHeightType,
imageSize.height, bgPositioningArea.height);
}
}
break;
}
}
imageSize.width = NSCoordSaturatingMultiply(imageSize.width, scaleX);
imageSize.height = NSCoordSaturatingMultiply(imageSize.height, scaleY);
// Compute the position of the background now that the background's size is
// determined.
ComputeBackgroundAnchorPoint(aLayer, bgPositioningArea.Size(), imageSize,
&imageTopLeft, &anchor);
imageTopLeft += offset;
anchor += offset;
nsRect destArea(imageTopLeft + aBorderArea.TopLeft(), imageSize);
nsRect fillArea = destArea;
PRIntn repeat = aLayer.mRepeat;
PR_STATIC_ASSERT(NS_STYLE_BG_REPEAT_XY ==
(NS_STYLE_BG_REPEAT_X | NS_STYLE_BG_REPEAT_Y));
if (repeat & NS_STYLE_BG_REPEAT_X) {
fillArea.x = aBGClipRect.x;
fillArea.width = aBGClipRect.width;

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

@ -269,11 +269,16 @@
#define NS_STYLE_BG_POSITION_RIGHT (1<<4)
// See nsStyleBackground
// Code depends on (BG_REPEAT_X | BG_REPEAT_Y) == BG_REPEAT_XY
#define NS_STYLE_BG_REPEAT_OFF 0x00
#define NS_STYLE_BG_REPEAT_X 0x01
#define NS_STYLE_BG_REPEAT_Y 0x02
#define NS_STYLE_BG_REPEAT_XY 0x03
// See nsStyleBackground
#define NS_STYLE_BG_SIZE_CONTAIN 0
#define NS_STYLE_BG_SIZE_COVER 1
// See nsStyleTable
#define NS_STYLE_BORDER_COLLAPSE 0
#define NS_STYLE_BORDER_SEPARATE 1

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

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: auto auto;</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: auto auto;
}
</style>
</head>
<body>
<div id="outer"></div>
</body>
</html>

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

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: auto 16px; reference</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 16px;
height: 16px;
background-image: url(aqua-32x32.png);
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: auto 16px;</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 64px;
height: 128px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: auto 16px;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: auto 12.5%;</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 64px;
height: 128px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: auto 12.5%;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: auto; reference</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 32px;
height: 32px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: auto;</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: auto;
}
</style>
</head>
<body>
<div id="outer"></div>
</body>
</html>

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

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: contain; on body, no-repeat, fixed</title>
<style type="text/css">
body
{
background-image: url(aqua-32x32.png);
background-attachment: fixed;
background-repeat: no-repeat;
-moz-background-size: contain;
}
</style>
</head>
<body>
</body>
</html>

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

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: contain; not fixed, no-repeat on body</title>
<style type="text/css">
body
{
background-image: url(aqua-32x32.png);
background-attachment: scroll;
background-repeat: no-repeat;
-moz-background-size: contain;
}
</style>
</head>
<body>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: contain; fixed, repeat on body</title>
<style type="text/css">
body
{
background-image: url(aqua-32x32.png);
background-attachment: fixed;
-moz-background-size: contain;
}
</style>
</head>
<body>
</body>
</html>

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

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: cover; on body, no-repeat, fixed</title>
<style type="text/css">
body
{
background-image: url(aqua-32x32.png);
background-attachment: fixed;
background-repeat: no-repeat;
-moz-background-size: cover;
}
</style>
</head>
<body>
</body>
</html>

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

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: cover; no-repeat, not-fixed on body</title>
<style type="text/css">
body
{
background-image: url(aqua-32x32.png);
background-attachment: scroll;
background-repeat: no-repeat;
-moz-background-size: cover;
}
</style>
</head>
<body>
</body>
</html>

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

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: cover; on body reference</title>
<style type="text/css">
body
{
background-image: url(aqua-32x32.png);
}
</style>
</head>
<body>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: cover; on body</title>
<style type="text/css">
body
{
background-image: url(aqua-32x32.png);
background-attachment: fixed;
-moz-background-size: cover;
}
</style>
</head>
<body>
</body>
</html>

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

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 100% 100%; no-repeat/fixed on body</title>
<style type="text/css">
body
{
background-image: url(aqua-32x32.png);
background-attachment: fixed;
-moz-background-size: 100% 100%;
background-repeat: no-repeat;
}
</style>
</head>
<body>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 100% 100%; no-repeat/not fixed on body</title>
<style type="text/css">
body
{
background-image: url(aqua-32x32.png);
background-attachment: scroll;
-moz-background-size: 100% 100%;
}
</style>
</head>
<body>
</body>
</html>

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

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 100% 100%; on body</title>
<style type="text/css">
body
{
background-image: url(green-16x20.png);
}
</style>
</head>
<body>
</body>
</html>

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

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 100% 100%; on body</title>
<style type="text/css">
body
{
background-image: url(green-8x20-blue-8x20-vertical.png);
background-repeat: no-repeat;
background-attachment: fixed;
overflow: hidden;
/*
* This should not affect how the background paints, that is, how the
* background image is sized:
*
* If the background-attachment value for this image is fixed [...] the
* background positioning area is the initial containing block [CSS21].
*
* Thus '100% 100%' below is relative to the viewport size, so we expect to
* see a background which, modulo aliasing, is half green and half blue.
*/
height: 10000px;
-moz-background-size: 100% 100%;
}
</style>
</head>
<body>
</body>
</html>

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

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 100% 100%; on body reference</title>
<style type="text/css">
body
{
background-image: url(aqua-32x32.png);
}
</style>
</head>
<body>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 100% 100%; on body</title>
<style type="text/css">
body
{
background-image: url(aqua-32x32.png);
background-attachment: fixed;
-moz-background-size: 100% 100%;
}
</style>
</head>
<body>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: contain; on body</title>
<style type="text/css">
body
{
background-image: url(aqua-32x32.png);
background-attachment: scroll;
background-repeat: no-repeat;
}
</style>
</head>
<body>
</body>
</html>

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

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<title>background-break: bounding-box</title>
<style type="text/css">
@font-face
{
font-family: Ahem;
src: url(../fonts/Ahem.ttf);
}
#outer
{
border: 1px solid black;
width: 10em;
}
#ahem-lines
{
font-family: Ahem;
font-size: 32px;
white-space: pre;
background-image: url(blue-8x20-green-8x20.png);
background-repeat: no-repeat;
-moz-background-inline-policy: bounding-box;
}
</style>
</head>
<body>
<div id="outer">
<span id="ahem-lines"> <!-- EOL -->
<!-- mix it up for each-box and bounding-box --><!-- EOL -->
<!-- EOL -->
<!-- EOL -->
</span></div>
</body>
</html>

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

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: contain; -moz-background-clip: border reference</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
border: 20px solid white;
width: 24px;
height: 88px;
}
#innermost
{
width: 24px;
height: 24px;
background-image: url(aqua-32x32.png);
}
</style>
</head>
<body>
<div id="outer"><div id="inner"><div id="innermost"></div></div></div>
</body>
</html>

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

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: contain; -moz-background-clip: border</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
border: 20px solid transparent;
width: 24px;
height: 88px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: contain;
-moz-background-clip: border;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: contain; -moz-background-clip: padding reference, -moz-background-origin: border</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
border: 20px solid white;
width: 24px;
height: 88px;
}
#innermost1
{
width: 24px;
height: 44px;
background-image: url(aqua-32x32.png);
}
#innermost2
{
width: 24px;
height: 44px;
background-color: lime;
}
</style>
</head>
<body>
<div id="outer"><div
id="inner"><div
id="innermost1"></div><div
id="innermost2"></div
></div
></div>
</body>
</html>

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

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: contain; -moz-background-clip: padding, -moz-background-origin: border</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
border: 20px solid transparent;
padding: 10px;
width: 4px;
height: 68px;
background-image: url(aqua-32x32.png);
background-color: lime;
background-repeat: no-repeat;
-moz-background-size: contain;
-moz-background-clip: padding;
-moz-background-origin: border;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: contain; -moz-background-clip: padding reference, -moz-background-origin: border</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
border: 20px solid white;
width: 24px;
height: 88px;
}
#innermost
{
width: 24px;
height: 44px;
background-image: url(aqua-32x32.png);
}
</style>
</head>
<body>
<div id="outer"><div id="inner"><div id="innermost"></div></div></div>
</body>
</html>

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

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: contain; -moz-background-clip: padding, -moz-background-origin: border</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
border: 20px solid transparent;
width: 24px;
height: 88px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: contain;
-moz-background-clip: padding;
-moz-background-origin: border;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: contain; -moz-background-clip: padding reference</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
border: 20px solid white;
width: 24px;
height: 88px;
}
#innermost
{
width: 24px;
height: 24px;
background-image: url(aqua-32x32.png);
}
</style>
</head>
<body>
<div id="outer"><div id="inner"><div id="innermost"></div></div></div>
</body>
</html>

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

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: contain; -moz-background-clip: padding</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
border: 20px solid transparent;
width: 24px;
height: 88px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: contain;
-moz-background-clip: padding;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: contain; background-position: 50% 50% reference</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner1
{
width: 64px;
height: 32px;
}
#inner2
{
width: 64px;
height: 64px;
background-image: url(aqua-32x32.png);
}
</style>
</head>
<body>
<div id="outer"><div id="inner1"></div><div id="inner2"></div></div>
</body>
</html>

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

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: contain; background-position: 50% 50%</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 64px;
height: 128px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: contain;
background-position: 50% 50%;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: contain; reference</title>
<style type="text/css">
#outer
{
border: 10px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 64px;
height: 64px;
background-image: url(aqua-32x32.png);
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: contain;</title>
<style type="text/css">
#outer
{
border: 10px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 64px;
height: 128px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: contain;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<title>background-break: continuous</title>
<style type="text/css">
@font-face
{
font-family: Ahem;
src: url(../fonts/Ahem.ttf);
}
#outer
{
border: 1px solid black;
width: 10em;
}
#ahem-lines
{
font-family: Ahem;
font-size: 32px;
white-space: pre;
background-image: url(blue-8x20-green-8x20.png);
background-repeat: no-repeat;
-moz-background-inline-policy: continuous;
}
</style>
</head>
<body>
<div id="outer">
<span id="ahem-lines"> <!-- EOL -->
<!-- mix it up for each-box and bounding-box --><!-- EOL -->
<!-- EOL -->
<!-- EOL -->
</span></div>
</body>
</html>

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

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: cover; background-break: bounding-box</title>
<style type="text/css">
@font-face
{
font-family: Ahem;
src: url(../fonts/Ahem.ttf);
}
#outer
{
border: 1px solid black;
width: 10em;
}
#ahem-lines
{
font-family: Ahem;
font-size: 32px;
white-space: pre;
background-image: url(blue-8x20-green-8x20.png);
background-repeat: no-repeat;
-moz-background-size: cover;
-moz-background-inline-policy: bounding-box;
}
</style>
</head>
<body>
<div id="outer">
<span id="ahem-lines"> <!-- EOL -->
<!-- mix it up for each-box and bounding-box --><!-- EOL -->
<!-- EOL -->
<!-- EOL -->
</span></div>
</body>
</html>

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

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: cover; background-break: continuous</title>
<style type="text/css">
@font-face
{
font-family: Ahem;
src: url(../fonts/Ahem.ttf);
}
#outer
{
border: 1px solid black;
width: 10em;
}
#ahem-lines
{
font-family: Ahem;
font-size: 32px;
white-space: pre;
background-image: url(blue-8x20-green-8x20.png);
background-repeat: no-repeat;
-moz-background-size: cover;
-moz-background-inline-policy: continuous;
}
</style>
</head>
<body>
<div id="outer">
<span id="ahem-lines"> <!-- EOL -->
<!-- mix it up for each-box and bounding-box --><!-- EOL -->
<!-- EOL -->
<!-- EOL -->
</span></div>
</body>
</html>

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

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: cover; background-break: each-box</title>
<style type="text/css">
@font-face
{
font-family: Ahem;
src: url(../fonts/Ahem.ttf);
}
#outer
{
border: 1px solid black;
width: 10em;
}
#ahem-lines
{
font-family: Ahem;
font-size: 32px;
white-space: pre;
background-image: url(blue-8x20-green-8x20.png);
background-repeat: no-repeat;
-moz-background-size: cover;
-moz-background-inline-policy: each-box;
}
</style>
</head>
<body>
<div id="outer">
<span id="ahem-lines"> <!-- EOL -->
<!-- mix it up for each-box and bounding-box --><!-- EOL -->
<!-- EOL -->
<!-- EOL -->
</span></div>
</body>
</html>

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

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: cover; reference</title>
<style type="text/css">
#outer
{
border: 10px solid black;
width: 64px;
height: 128px;
background-image: url(aqua-32x32.png);
}
</style>
</head>
<body>
<div id="outer"></div>
</body>
</html>

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

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: cover;</title>
<style type="text/css">
#outer
{
border: 10px solid black;
width: 64px;
height: 128px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: cover;
}
</style>
</head>
<body>
<div id="outer"></div>
</body>
</html>

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

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<title>background-break: each-box</title>
<style type="text/css">
@font-face
{
font-family: Ahem;
src: url(../fonts/Ahem.ttf);
}
#outer
{
border: 1px solid black;
width: 10em;
}
#ahem-lines
{
font-family: Ahem;
font-size: 32px;
white-space: pre;
background-image: url(blue-8x20-green-8x20.png);
background-repeat: no-repeat;
-moz-background-inline-policy: each-box;
}
</style>
</head>
<body>
<div id="outer">
<span id="ahem-lines"> <!-- EOL -->
<!-- mix it up for each-box and bounding-box --><!-- EOL -->
<!-- EOL -->
<!-- EOL -->
</span></div>
</body>
</html>

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 16px auto;</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 64px;
height: 128px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: 16px auto;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 32px 64px; reference</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 32px;
height: 64px;
background-image: url(aqua-32x32.png);
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 32px 64px;</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 64px;
height: 128px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: 32px 64px;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 16px 25%;</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 16px;
height: 32px;
background-image: url(aqua-32x32.png);
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 16px 25%;</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 64px;
height: 128px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: 16px 25%;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 16px;</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 64px;
height: 128px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: 16px;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 32px auto; for image with no intrinsic height reference</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 32px;
height: 128px;
background-color: lime;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 32px auto; for image with no intrinsic height</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 64px;
height: 128px;
background-image: url(no-intrinsic-size.svg);
background-repeat: no-repeat;
-moz-background-size: 32px auto;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 32px auto; for image with no intrinsic size reference</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 64px;
height: 32px;
background-color: lime;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: auto 32px; for image with no intrinsic width</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 64px;
height: 128px;
background-image: url(no-intrinsic-size.svg);
background-repeat: no-repeat;
-moz-background-size: auto 32px;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 25% auto;</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 64px;
height: 128px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: 25% auto;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 25% 32px;</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 64px;
height: 128px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: 25% 32px;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 50% 25%; reference</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 32px;
height: 32px;
background-image: url(aqua-32x32.png);
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 100% 100%; stretch reference</title>
<style type="text/css">
#outer
{
border: 10px solid black;
width: 60px;
height: 120px;
}
#inner1
{
background: blue;
width: 15px;
height: 120px;
display: inline-block;
background-image: url(blue-16x20.png);
/* obscure sampling artifacts at the color boundary */
border-right: 5px solid black;
}
#inner2
{
background: lime;
width: 35px;
height: 120px;
display: inline-block;
background-image: url(green-16x20.png);
/* obscure sampling artifacts at the color boundary */
border-left: 5px solid black;
}
</style>
</head>
<body>
<div id="outer"><div id="inner1"></div><div id="inner2"></div></div>
</body>
</html>

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

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 100% 100%; stretch</title>
<style type="text/css">
#outer
{
border: 10px solid black;
width: 60px;
height: 120px;
}
#inner
{
width: 60px;
height: 120px;
background-image: url(blue-8x20-green-16x20.png);
background-repeat: no-repeat;
-moz-background-size: 100% 100%;
}
#innermost
{
width: 15px;
height: 120px;
/* obscure sampling artifacts at the color boundary */
border-right: 10px solid black;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"><div id="innermost"></div></div></div>
</body>
</html>

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 50% 25%;</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 64px;
height: 128px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: 50% 25%;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 25%;</title>
<style type="text/css">
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 64px;
height: 128px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: 25%;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size + zoom</title>
<style type="text/css">
html
{
margin: 0;
padding: 10px;
}
body
{
margin: 0;
padding: 0;
}
#outer
{
border: 2px solid black;
width: 128px;
height: 256px;
}
#inner
{
width: 32px;
height: 32px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html reftest-zoom="2">
<head>
<title>background-size + zoom</title>
<style type="text/css">
html
{
margin: 0;
padding: 5px;
}
body
{
margin: 0;
padding: 0;
}
#outer
{
border: 1px solid black;
width: 64px;
height: 128px;
}
#inner
{
width: 64px;
height: 128px;
background-image: url(aqua-32x32.png);
background-repeat: no-repeat;
-moz-background-size: 25%;
}
</style>
</head>
<body>
<div id="outer"><div id="inner"></div></div>
</body>
</html>

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

@ -0,0 +1,60 @@
<!DOCTYPE html>
<html>
<head>
<title>background-size: 64px 40px; repeat, zoom reference</title>
<style type="text/css">
html
{
margin: 0;
padding: 0;
}
body
{
margin: 0;
padding: 20px;
}
#outer
{
width: 512px;
height: 320px;
}
/*
* PRE-ZOOM:
* 2x size the image, then tile it 4x4 across the div; sampling artifacts at
* 32px horizontal offset, then every 64px for the full height of the div.
* POST-ZOOM:
* 4x size the image, then tile it 4x4 across the div; sampling artifacts at
* 64px horizontal offset, then every 128px for the full height of the div.
*/
/* Aargh, sampling artifacts, we hates them, precioussss. */
#outer > div
{
display: inline-block;
width: 56px;
height: 320px;
}
.blue
{
background: url(blue-16x20.png);
border-right: 8px solid black;
}
.green
{
background: url(green-16x20.png);
border-left: 8px solid black;
}
</style>
</head>
<body>
<div id="outer"><div
class="blue"></div><div
class="green"></div><div
class="blue"></div><div
class="green"></div><div
class="blue"></div><div
class="green"></div><div
class="blue"></div><div
class="green"></div></div>
</body>
</html>

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

@ -0,0 +1,61 @@
<!DOCTYPE html>
<html reftest-zoom="2">
<head>
<title>background-size: 64px 40px; repeat, zoom</title>
<style type="text/css">
html
{
margin: 0;
padding: 0;
}
body
{
margin: 0;
padding: 10px;
}
#outer
{
/*
* PRE-ZOOM:
* 2x size the image, then tile it 4x4 across the div; sampling artifacts at
* 32px horizontal offset, then every 64px for the full height of the div.
* POST-ZOOM:
* 4x size the image, then tile it 4x4 across the div; sampling artifacts at
* 64px horizontal offset, then every 128px for the full height of the div.
*/
width: 256px;
height: 160px;
background-image: url(blue-16x20-green-16x20.png);
background-repeat: repeat;
-moz-background-size: 64px 40px;
}
/* Aargh, sampling artifacts, we hates them, precioussss. */
#outer > div
{
display: inline-block;
width: 28px;
height: 160px;
}
.blue
{
border-right: 4px solid black;
}
.green
{
border-left: 4px solid black;
}
</style>
</head>
<body>
<div id="outer"><div
class="blue"></div><div
class="green"></div><div
class="blue"></div><div
class="green"></div><div
class="blue"></div><div
class="green"></div><div
class="blue"></div><div
class="green"></div></div>
</body>
</html>

Двоичные данные
layout/reftests/backgrounds/green-8x20-blue-8x20-vertical.png Normal file

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

После

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

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

@ -0,0 +1,8 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<svg xmlns="http://www.w3.org/2000/svg">
<title>Image with no intrinsic size</title>
<rect width="100%" height="100%" fill="lime"/>
</svg>

После

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

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

@ -24,3 +24,72 @@
== continuous-inline-4b.html continuous-inline-4-ref.html
== continuous-inline-5a.html continuous-inline-5-ref.html
== continuous-inline-5b.html continuous-inline-5-ref.html
== background-size-auto-auto.html background-size-auto-ref.html
== background-size-auto.html background-size-auto-ref.html
== background-size-contain.html background-size-contain-ref.html
== background-size-cover.html background-size-cover-ref.html
== background-size-auto-length.html background-size-auto-length-ref.html
== background-size-length-auto.html background-size-auto-length-ref.html
== background-size-length.html background-size-auto-length-ref.html
== background-size-auto-percent.html background-size-auto-length-ref.html
== background-size-percent-auto.html background-size-auto-length-ref.html
== background-size-percent.html background-size-auto-length-ref.html
== background-size-length-percent.html background-size-length-percent-ref.html
== background-size-percent-length.html background-size-length-percent-ref.html
== background-size-percent-percent.html background-size-percent-percent-ref.html
== background-size-length-length.html background-size-length-length-ref.html
== background-size-percent-percent-stretch.html background-size-percent-percent-stretch-ref.html
== background-size-body-percent-percent.html background-size-body-percent-percent-ref.html
== background-size-body-percent-percent-no-repeat.html background-size-body-percent-percent-ref.html
== background-size-body-percent-percent-not-fixed.html background-size-body-percent-percent-ref.html
== background-size-body-cover.html background-size-body-cover-ref.html
== background-size-body-cover-no-repeat.html background-size-body-cover-ref.html
!= background-size-body-cover-not-fixed.html background-size-body-cover-ref.html
!= background-size-body-cover-not-fixed.html background-size-body-single-not-fixed.html
# relies on reftest window having greater height than width
== background-size-body-contain.html background-size-body-cover-ref.html
!= background-size-body-contain-no-repeat.html background-size-body-cover-ref.html
!= background-size-body-contain-not-fixed.html background-size-body-cover-ref.html
!= background-size-body-cover-not-fixed.html background-size-body-contain-not-fixed.html
!= background-size-body-percent-percent-overflow.html background-size-body-percent-percent-overflow-ref.html
== background-size-zoom-no-repeat.html background-size-zoom-no-repeat-ref.html
== background-size-contain-clip-padding.html background-size-contain-clip-padding-ref.html
== background-size-contain-clip-border.html background-size-contain-clip-border-ref.html
== background-size-contain-position-fifty-fifty.html background-size-contain-position-fifty-fifty-ref.html
== background-size-contain-clip-padding-origin-border.html background-size-contain-clip-padding-origin-border-ref.html
== background-size-contain-clip-padding-origin-border-padding.html background-size-contain-clip-padding-origin-border-padding-ref.html
# -moz-background-inline-policy is touchy and hard to test due to stretching
# artifacts and the difficulty of covering exact lines, and its CSS3 analog is
# on the chopping block at the moment, so just make sure background-size results
# in a different rendering when present.
!= background-size-cover-continuous.html background-size-continuous.html
!= background-size-cover-each-box.html background-size-each-box.html
!= background-size-cover-bounding-box.html background-size-bounding-box.html
# ...and make sure each rendering with background-size is different from the
# others
!= background-size-cover-continuous.html background-size-cover-each-box.html
!= background-size-cover-continuous.html background-size-cover-bounding-box.html
!= background-size-cover-each-box.html background-size-cover-bounding-box.html
# There seems to be a pixel-snapping problem here, where the repeated background
# image isn't being snapped at its boundaries. Note that the boundaries within
# the image aren't the issue, because they're being obscured to avoid sampling
# algorithm dependencies (at least assuming the sampling algorithm in use
# doesn't sample too far astray from the boundaries).
fails == background-size-zoom-repeat.html background-size-zoom-repeat-ref.html
# background-size affects images without intrinsic dimensions specially; we may
# not support such image formats right now, but when we do, we want
# background-size to be changed accordingly, and hopefully these tests should
# start failing when we do.
fails == background-size-no-intrinsic-width-image.html background-size-no-intrinsic-width-image-ref.html
fails == background-size-no-intrinsic-height-image.html background-size-no-intrinsic-height-image-ref.html

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

@ -174,11 +174,16 @@ PRBool nsCSSDeclaration::AppendValueToString(nsCSSProperty aProperty, nsAString&
((aProperty == eCSSProperty_background_position ||
aProperty == eCSSProperty__moz_transform_origin) &&
pair->mXValue.GetUnit() != eCSSUnit_Inherit &&
pair->mXValue.GetUnit() != eCSSUnit_Initial)) {
// Only output a Y value if it's different from the X value
pair->mXValue.GetUnit() != eCSSUnit_Initial) ||
(aProperty == eCSSProperty__moz_background_size &&
pair->mXValue.GetUnit() != eCSSUnit_Inherit &&
pair->mXValue.GetUnit() != eCSSUnit_Initial &&
pair->mXValue.GetUnit() != eCSSUnit_Enumerated)) {
// Only output a Y value if it's different from the X value,
// or if it's a background-position value other than 'initial'
// or 'inherit' or if it's a -moz-transform-origin value other
// than 'initial' or 'inherit'.
// or 'inherit', or if it's a -moz-transform-origin value other
// than 'initial' or 'inherit', or if it's a -moz-background-size
// value other than 'initial' or 'inherit' or 'contain' or 'cover'.
aResult.Append(PRUnichar(' '));
AppendCSSValueToString(aProperty, pair->mYValue, aResult);
}
@ -772,6 +777,8 @@ nsCSSDeclaration::GetValue(nsCSSProperty aProperty,
* data->ValueListStorageFor(eCSSProperty__moz_background_clip);
const nsCSSValueList *origin =
* data->ValueListStorageFor(eCSSProperty__moz_background_origin);
const nsCSSValuePairList *size =
* data->ValuePairListStorageFor(eCSSProperty__moz_background_size);
for (;;) {
AppendCSSValueToString(eCSSProperty_background_image,
image->mValue, aValue);
@ -800,7 +807,7 @@ nsCSSDeclaration::GetValue(nsCSSProperty aProperty,
// support for content-box on background-clip.
PR_STATIC_ASSERT(NS_STYLE_BG_CLIP_BORDER ==
NS_STYLE_BG_ORIGIN_BORDER);
PR_STATIC_ASSERT(NS_STYLE_BG_CLIP_PADDING ==
PR_STATIC_ASSERT(NS_STYLE_BG_CLIP_PADDING ==
NS_STYLE_BG_ORIGIN_PADDING);
// PR_STATIC_ASSERT(NS_STYLE_BG_CLIP_CONTENT == /* does not exist */
// NS_STYLE_BG_ORIGIN_CONTENT);
@ -824,16 +831,17 @@ nsCSSDeclaration::GetValue(nsCSSProperty aProperty,
position = position->mNext;
clip = clip->mNext;
origin = origin->mNext;
size = size->mNext;
if (!image) {
if (repeat || attachment || position || clip || origin) {
if (repeat || attachment || position || clip || origin || size) {
// Uneven length lists, so can't be serialized as shorthand.
aValue.Truncate();
return NS_OK;
}
break;
}
if (!repeat || !attachment || !position || !clip || !origin) {
if (!repeat || !attachment || !position || !clip || !origin || !size) {
// Uneven length lists, so can't be serialized as shorthand.
aValue.Truncate();
return NS_OK;

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

@ -241,11 +241,13 @@ CSS_KEY(code, code)
CSS_KEY(col-resize, col_resize)
CSS_KEY(collapse, collapse)
CSS_KEY(condensed, condensed)
CSS_KEY(contain, contain)
CSS_KEY(content, content)
CSS_KEY(content-box, content_box)
CSS_KEY(context-menu, context_menu)
CSS_KEY(continuous, continuous)
CSS_KEY(copy, copy)
CSS_KEY(cover, cover)
CSS_KEY(crop, crop)
CSS_KEY(cross, cross)
CSS_KEY(crosshair, crosshair)

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

@ -26,6 +26,7 @@
* Boris Zbarsky <bzbarsky@mit.edu>
* Mats Palmgren <mats.palmgren@bredband.net>
* Christian Biesinger <cbiesinger@web.de>
* Jeff Walden <jwalden+code@mit.edu>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -407,6 +408,7 @@ protected:
nsCSSValuePair mPosition;
nsCSSValue mClip;
nsCSSValue mOrigin;
nsCSSValuePair mSize;
// The background-color is set as a side-effect, and if so, mLastItem
// is set to true.
PRBool mLastItem;
@ -421,6 +423,8 @@ protected:
PRBool ParseBackgroundList(nsCSSProperty aPropID); // a single value prop-id
PRBool ParseBackgroundPosition();
PRBool ParseBoxPositionValues(nsCSSValuePair& aOut);
PRBool ParseBackgroundSize();
PRBool ParseBackgroundSizeValues(nsCSSValuePair& aOut);
PRBool ParseBorderColor();
PRBool ParseBorderColors(nsCSSValueList** aResult,
nsCSSProperty aProperty);
@ -5061,6 +5065,8 @@ CSSParserImpl::ParseProperty(nsCSSProperty aPropID)
case eCSSProperty__moz_background_origin:
case eCSSProperty_background_repeat:
return ParseBackgroundList(aPropID);
case eCSSProperty__moz_background_size:
return ParseBackgroundSize();
case eCSSProperty_border:
return ParseBorderSide(kBorderTopIDs, PR_TRUE);
case eCSSProperty_border_color:
@ -5341,6 +5347,7 @@ CSSParserImpl::ParseSingleValueProperty(nsCSSValue& aValue,
case eCSSProperty_border_start:
case eCSSProperty_border_top:
case eCSSProperty_border_width:
case eCSSProperty__moz_background_size:
case eCSSProperty__moz_border_radius:
case eCSSProperty__moz_border_radius_topLeft:
case eCSSProperty__moz_border_radius_topRight:
@ -5986,6 +5993,7 @@ CSSParserImpl::ParseBackground()
BackgroundItem bgitem;
nsCSSValuePairList *positionHead = nsnull, **positionTail = &positionHead;
nsCSSValuePairList *sizeHead = nsnull, **sizeTail = &sizeHead;
static const BackgroundItemSimpleValueInfo simpleValues[] = {
{ &BackgroundItem::mImage, eCSSProperty_background_image },
{ &BackgroundItem::mRepeat, eCSSProperty_background_repeat },
@ -6003,6 +6011,7 @@ CSSParserImpl::ParseBackground()
if (!ParseBackgroundItem(bgitem, !positionHead)) {
break;
}
nsCSSValuePairList *positionItem = new nsCSSValuePairList;
if (!positionItem) {
mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY);
@ -6013,6 +6022,16 @@ CSSParserImpl::ParseBackground()
*positionTail = positionItem;
positionTail = &positionItem->mNext;
nsCSSValuePairList *sizeItem = new nsCSSValuePairList;
if (!sizeItem) {
mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY);
break;
}
sizeItem->mXValue = bgitem.mSize.mXValue;
sizeItem->mYValue = bgitem.mSize.mYValue;
*sizeTail = sizeItem;
sizeTail = &sizeItem->mNext;
PRBool fail = PR_FALSE;
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(simpleValues); ++i) {
nsCSSValueList *item = new nsCSSValueList;
@ -6037,6 +6056,7 @@ CSSParserImpl::ParseBackground()
}
mTempData.mColor.mBackPosition = positionHead;
mTempData.mColor.mBackSize = sizeHead;
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(simpleValues); ++i) {
nsCSSValueList **source = static_cast<nsCSSValueList**>(
mTempData.PropertyAt(simpleValues[i].propID));
@ -6049,9 +6069,11 @@ CSSParserImpl::ParseBackground()
mTempData.SetPropertyBit(eCSSProperty_background_position);
mTempData.SetPropertyBit(eCSSProperty__moz_background_clip);
mTempData.SetPropertyBit(eCSSProperty__moz_background_origin);
mTempData.SetPropertyBit(eCSSProperty__moz_background_size);
return PR_TRUE;
}
delete positionHead;
delete sizeHead;
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(simpleValues); ++i) {
delete simpleHeads[i];
}
@ -6073,6 +6095,8 @@ CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundItem& aItem,
aItem.mPosition.mYValue.SetPercentValue(0.0f);
aItem.mClip.SetIntValue(NS_STYLE_BG_CLIP_BORDER, eCSSUnit_Enumerated);
aItem.mOrigin.SetIntValue(NS_STYLE_BG_ORIGIN_PADDING, eCSSUnit_Enumerated);
aItem.mSize.mXValue.SetAutoValue();
aItem.mSize.mYValue.SetAutoValue();
aItem.mLastItem = PR_FALSE;
PRBool haveColor = PR_FALSE,
@ -6113,6 +6137,8 @@ CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundItem& aItem,
aItem.mPosition.SetBothValuesTo(val);
aItem.mClip = val;
aItem.mOrigin = val;
aItem.mSize.mXValue = val;
aItem.mSize.mYValue = val;
aItem.mLastItem = PR_TRUE;
haveSomething = PR_TRUE;
break;
@ -6160,9 +6186,9 @@ CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundItem& aItem,
// support for content-box on background-clip.
} else if (nsCSSProps::FindKeyword(keyword,
nsCSSProps::kBackgroundClipKTable, dummy)) {
// For now, we use the background-clip table, because we don't
// support 'content' on background-clip. But that's dangerous
// if we eventually support no-clip.
// For now, we use the background-clip table rather than have a special
// background-origin table, because we don't support 'content-box' on
// background-origin.
NS_ASSERTION(
nsCSSProps::kBackgroundClipKTable[0] == eCSSKeyword_border &&
nsCSSProps::kBackgroundClipKTable[2] == eCSSKeyword_padding &&
@ -6230,7 +6256,8 @@ CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundItem& aItem,
return haveSomething;
}
// This function is very similar to ParseBackgroundPosition.
// This function is very similar to ParseBackgroundPosition and
// ParseBackgroundSize.
PRBool
CSSParserImpl::ParseBackgroundList(nsCSSProperty aPropID)
{
@ -6271,7 +6298,7 @@ CSSParserImpl::ParseBackgroundList(nsCSSProperty aPropID)
return PR_FALSE;
}
// This function is very similar to ParseBackgroundList.
// This function is very similar to ParseBackgroundList and ParseBackgroundSize.
PRBool
CSSParserImpl::ParseBackgroundPosition()
{
@ -6316,7 +6343,7 @@ CSSParserImpl::ParseBackgroundPosition()
* values corresponding to percentages of the box, raw offsets, or keywords
* like "top," "left center," etc.
*
* @param aOut The nsCSSValuePair where to place the result.
* @param aOut The nsCSSValuePair in which to place the result.
* @return Whether or not the operation succeeded.
*/
PRBool CSSParserImpl::ParseBoxPositionValues(nsCSSValuePair &aOut)
@ -6398,6 +6425,90 @@ PRBool CSSParserImpl::ParseBoxPositionValues(nsCSSValuePair &aOut)
return PR_TRUE;
}
// This function is very similar to ParseBackgroundList and
// ParseBackgroundPosition.
PRBool
CSSParserImpl::ParseBackgroundSize()
{
nsCSSValuePair valuePair;
nsCSSValuePairList *head = nsnull, **tail = &head;
if (ParseVariant(valuePair.mXValue, VARIANT_INHERIT, nsnull)) {
// 'initial' and 'inherit' stand alone, no second value.
head = new nsCSSValuePairList;
if (!head) {
mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY);
return PR_FALSE;
}
head->mXValue = valuePair.mXValue;
head->mYValue.Reset();
mTempData.mColor.mBackSize = head;
mTempData.SetPropertyBit(eCSSProperty__moz_background_size);
return ExpectEndProperty();
}
for (;;) {
if (!ParseBackgroundSizeValues(valuePair)) {
break;
}
nsCSSValuePairList *item = new nsCSSValuePairList;
if (!item) {
mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY);
break;
}
item->mXValue = valuePair.mXValue;
item->mYValue = valuePair.mYValue;
*tail = item;
tail = &item->mNext;
if (ExpectSymbol(',', PR_TRUE)) {
continue;
}
if (!ExpectEndProperty()) {
break;
}
mTempData.mColor.mBackSize = head;
mTempData.SetPropertyBit(eCSSProperty__moz_background_size);
return PR_TRUE;
}
delete head;
return PR_FALSE;
}
/**
* Parses two values that correspond to lengths for the -moz-background-size
* property. These can be one or two lengths (or the 'auto' keyword) or
* percentages corresponding to the element's dimensions or the single keywords
* 'contain' or 'cover'. 'initial' and 'inherit' must be handled by the caller
* if desired.
*
* @param aOut The nsCSSValuePair in which to place the result.
* @return Whether or not the operation succeeded.
*/
PRBool CSSParserImpl::ParseBackgroundSizeValues(nsCSSValuePair &aOut)
{
// First try a percentage or a length value
nsCSSValue &xValue = aOut.mXValue,
&yValue = aOut.mYValue;
if (ParseNonNegativeVariant(xValue, VARIANT_LP | VARIANT_AUTO, nsnull)) {
// We have one percentage/length/auto. Get the optional second
// percentage/length/keyword.
if (ParseNonNegativeVariant(yValue, VARIANT_LP | VARIANT_AUTO, nsnull)) {
// We have a second percentage/length/auto.
return PR_TRUE;
}
// If only one percentage or length value is given, it sets the
// horizontal size only, and the vertical size will be as if by 'auto'.
yValue.SetAutoValue();
return PR_TRUE;
}
// Now address 'contain' and 'cover'.
if (!ParseEnum(xValue, nsCSSProps::kBackgroundSizeKTable))
return PR_FALSE;
yValue.Reset();
return PR_TRUE;
}
PRBool
CSSParserImpl::ParseBorderColor()
{

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

@ -470,6 +470,16 @@ CSS_PROP_BACKGROUND(
mBackRepeat,
eCSSType_ValueList,
kBackgroundRepeatKTable)
CSS_PROP_BACKGROUND(
-moz-background-size,
_moz_background_size,
MozBackgroundSize,
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
CSS_PROPERTY_VALUE_LIST_USES_COMMAS,
Color,
mBackSize,
eCSSType_ValuePairList,
kBackgroundSizeKTable)
CSS_PROP_DISPLAY(
-moz-binding,
binding,

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

@ -527,6 +527,12 @@ const PRInt32 nsCSSProps::kBackgroundRepeatKTable[] = {
eCSSKeyword_UNKNOWN,-1
};
const PRInt32 nsCSSProps::kBackgroundSizeKTable[] = {
eCSSKeyword_contain, NS_STYLE_BG_SIZE_CONTAIN,
eCSSKeyword_cover, NS_STYLE_BG_SIZE_COVER,
eCSSKeyword_UNKNOWN,-1
};
const PRInt32 nsCSSProps::kBorderCollapseKTable[] = {
eCSSKeyword_collapse, NS_STYLE_BORDER_COLLAPSE,
eCSSKeyword_separate, NS_STYLE_BORDER_SEPARATE,
@ -1502,6 +1508,7 @@ static const nsCSSProperty gBackgroundSubpropTable[] = {
eCSSProperty_background_position,
eCSSProperty__moz_background_clip,
eCSSProperty__moz_background_origin,
eCSSProperty__moz_background_size,
eCSSProperty_UNKNOWN
};

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

@ -170,6 +170,7 @@ public:
static const PRInt32 kBackgroundOriginKTable[];
static const PRInt32 kBackgroundPositionKTable[];
static const PRInt32 kBackgroundRepeatKTable[];
static const PRInt32 kBackgroundSizeKTable[];
static const PRInt32 kBorderCollapseKTable[];
static const PRInt32 kBorderColorKTable[];
static const PRInt32 kBorderImageKTable[];

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

@ -110,6 +110,7 @@ nsCSSColor::nsCSSColor(void)
, mBackRepeat(nsnull)
, mBackAttachment(nsnull)
, mBackPosition(nsnull)
, mBackSize(nsnull)
, mBackClip(nsnull)
, mBackOrigin(nsnull)
{
@ -124,6 +125,7 @@ nsCSSColor::~nsCSSColor(void)
delete mBackRepeat;
delete mBackAttachment;
delete mBackPosition;
delete mBackSize;
delete mBackClip;
delete mBackOrigin;
}

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

@ -312,6 +312,7 @@ struct nsCSSColor : public nsCSSStruct {
nsCSSValueList* mBackRepeat;
nsCSSValueList* mBackAttachment;
nsCSSValuePairList* mBackPosition;
nsCSSValuePairList* mBackSize;
nsCSSValueList* mBackClip;
nsCSSValueList* mBackOrigin;
nsCSSValue mBackInlinePolicy;

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

@ -1209,7 +1209,7 @@ nsComputedDOMStyle::GetBackgroundList(PRUint8 nsStyleBackground::Layer::* aMembe
delete valueList;
return NS_ERROR_OUT_OF_MEMORY;
}
val->SetIdent(nsCSSProps::ValueToKeywordEnum(bg->mLayers[i].*aMember,
val->SetIdent(nsCSSProps::ValueToKeywordEnum(bg->mLayers[i].*aMember,
aTable));
}
@ -1358,6 +1358,82 @@ nsComputedDOMStyle::GetBackgroundRepeat(nsIDOMCSSValue** aValue)
aValue);
}
nsresult
nsComputedDOMStyle::GetMozBackgroundSize(nsIDOMCSSValue** aValue)
{
const nsStyleBackground* bg = GetStyleBackground();
nsDOMCSSValueList *valueList = GetROCSSValueList(PR_TRUE);
NS_ENSURE_TRUE(valueList, NS_ERROR_OUT_OF_MEMORY);
for (PRUint32 i = 0, i_end = bg->mSizeCount; i < i_end; ++i) {
const nsStyleBackground::Size &size = bg->mLayers[i].mSize;
switch (size.mWidthType) {
case nsStyleBackground::Size::eContain:
case nsStyleBackground::Size::eCover: {
NS_ABORT_IF_FALSE(size.mWidthType == size.mHeightType,
"unsynced types");
nsCSSKeyword keyword = size.mWidthType == nsStyleBackground::Size::eContain
? eCSSKeyword_contain
: eCSSKeyword_cover;
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
if (!val || !valueList->AppendCSSValue(val)) {
delete valueList;
delete val;
return NS_ERROR_OUT_OF_MEMORY;
}
val->SetIdent(keyword);
break;
}
default: {
nsDOMCSSValueList *itemList = GetROCSSValueList(PR_FALSE);
if (!itemList || !valueList->AppendCSSValue(itemList)) {
delete valueList;
delete itemList;
return NS_ERROR_OUT_OF_MEMORY;
}
nsROCSSPrimitiveValue* valX = GetROCSSPrimitiveValue();
nsROCSSPrimitiveValue* valY = GetROCSSPrimitiveValue();
if (!valX || !itemList->AppendCSSValue(valX)) {
delete valueList;
delete valX;
return NS_ERROR_OUT_OF_MEMORY;
}
if (!valY || !itemList->AppendCSSValue(valY)) {
delete valueList;
delete valY;
return NS_ERROR_OUT_OF_MEMORY;
}
if (size.mWidthType == nsStyleBackground::Size::eAuto) {
valX->SetIdent(eCSSKeyword_auto);
} else if (size.mWidthType == nsStyleBackground::Size::ePercentage) {
valX->SetPercent(size.mWidth.mFloat);
} else {
NS_ABORT_IF_FALSE(size.mWidthType == nsStyleBackground::Size::eLength,
"bad mWidthType");
valX->SetAppUnits(size.mWidth.mCoord);
}
if (size.mHeightType == nsStyleBackground::Size::eAuto) {
valY->SetIdent(eCSSKeyword_auto);
} else if (size.mHeightType == nsStyleBackground::Size::ePercentage) {
valY->SetPercent(size.mHeight.mFloat);
} else {
NS_ABORT_IF_FALSE(size.mHeightType == nsStyleBackground::Size::eLength,
"bad mHeightType");
valY->SetAppUnits(size.mHeight.mCoord);
}
break;
}
}
}
return CallQueryInterface(valueList, aValue);
}
nsresult
nsComputedDOMStyle::GetPadding(nsIDOMCSSValue** aValue)
{
@ -4216,6 +4292,7 @@ nsComputedDOMStyle::GetQueryablePropertyMap(PRUint32* aLength)
COMPUTED_STYLE_MAP_ENTRY(_moz_background_clip, BackgroundClip),
COMPUTED_STYLE_MAP_ENTRY(_moz_background_inline_policy, BackgroundInlinePolicy),
COMPUTED_STYLE_MAP_ENTRY(_moz_background_origin, BackgroundOrigin),
COMPUTED_STYLE_MAP_ENTRY(_moz_background_size, MozBackgroundSize),
COMPUTED_STYLE_MAP_ENTRY(binding, Binding),
COMPUTED_STYLE_MAP_ENTRY(border_bottom_colors, BorderBottomColors),
COMPUTED_STYLE_MAP_ENTRY(border_image, BorderImage),

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

@ -175,6 +175,7 @@ private:
nsresult GetBackgroundClip(nsIDOMCSSValue** aValue);
nsresult GetBackgroundInlinePolicy(nsIDOMCSSValue** aValue);
nsresult GetBackgroundOrigin(nsIDOMCSSValue** aValue);
nsresult GetMozBackgroundSize(nsIDOMCSSValue** aValue);
/* Padding properties */
nsresult GetPadding(nsIDOMCSSValue** aValue);

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

@ -1446,6 +1446,7 @@ nsRuleNode::GetBackgroundData(nsStyleContext* aContext)
colorData.mBackRepeat = nsnull;
colorData.mBackAttachment = nsnull;
colorData.mBackPosition = nsnull;
colorData.mBackSize = nsnull;
colorData.mBackClip = nsnull;
colorData.mBackOrigin = nsnull;
@ -3871,6 +3872,91 @@ struct BackgroundItemComputer<nsCSSValuePairList, nsStyleBackground::Position>
};
struct BackgroundSizeAxis {
nsCSSValue nsCSSValuePairList::* specified;
nsStyleBackground::Size::Dimension nsStyleBackground::Size::* result;
PRUint8 nsStyleBackground::Size::* type;
};
static const BackgroundSizeAxis gBGSizeAxes[] = {
{ &nsCSSValuePairList::mXValue,
&nsStyleBackground::Size::mWidth,
&nsStyleBackground::Size::mWidthType },
{ &nsCSSValuePairList::mYValue,
&nsStyleBackground::Size::mHeight,
&nsStyleBackground::Size::mHeightType }
};
NS_SPECIALIZE_TEMPLATE
struct BackgroundItemComputer<nsCSSValuePairList, nsStyleBackground::Size>
{
static void ComputeValue(nsStyleContext* aStyleContext,
const nsCSSValuePairList* aSpecifiedValue,
nsStyleBackground::Size& aComputedValue,
PRBool& aCanStoreInRuleTree)
{
nsStyleBackground::Size &size = aComputedValue;
for (const BackgroundSizeAxis *axis = gBGSizeAxes,
*axis_end = gBGSizeAxes + NS_ARRAY_LENGTH(gBGSizeAxes);
axis != axis_end; ++axis) {
const nsCSSValue &specified = aSpecifiedValue->*(axis->specified);
if (eCSSUnit_Auto == specified.GetUnit()) {
size.*(axis->type) = nsStyleBackground::Size::eAuto;
}
else if (eCSSUnit_Enumerated == specified.GetUnit()) {
PR_STATIC_ASSERT(nsStyleBackground::Size::eContain ==
NS_STYLE_BG_SIZE_CONTAIN);
PR_STATIC_ASSERT(nsStyleBackground::Size::eCover ==
NS_STYLE_BG_SIZE_COVER);
NS_ABORT_IF_FALSE(specified.GetIntValue() == NS_STYLE_BG_SIZE_CONTAIN ||
specified.GetIntValue() == NS_STYLE_BG_SIZE_COVER,
"invalid enumerated value for size coordinate");
size.*(axis->type) = specified.GetIntValue();
}
else if (eCSSUnit_Null == specified.GetUnit()) {
NS_ABORT_IF_FALSE(axis == gBGSizeAxes + 1,
"null allowed only as height value, and only "
"for contain/cover/initial/inherit");
#ifdef DEBUG
{
const nsCSSValue &widthValue = aSpecifiedValue->mXValue;
NS_ABORT_IF_FALSE(widthValue.GetUnit() != eCSSUnit_Inherit &&
widthValue.GetUnit() != eCSSUnit_Initial,
"initial/inherit should already have been handled");
NS_ABORT_IF_FALSE(widthValue.GetUnit() == eCSSUnit_Enumerated &&
(widthValue.GetIntValue() == NS_STYLE_BG_SIZE_CONTAIN ||
widthValue.GetIntValue() == NS_STYLE_BG_SIZE_COVER),
"null height value not corresponding to allowable "
"non-null width value");
}
#endif
size.*(axis->type) = size.mWidthType;
}
else if (eCSSUnit_Percent == specified.GetUnit()) {
(size.*(axis->result)).mFloat = specified.GetPercentValue();
size.*(axis->type) = nsStyleBackground::Size::ePercentage;
}
else {
NS_ABORT_IF_FALSE(specified.IsLengthUnit(), "unexpected unit");
(size.*(axis->result)).mCoord =
CalcLength(specified, aStyleContext, aStyleContext->PresContext(),
aCanStoreInRuleTree);
size.*(axis->type) = nsStyleBackground::Size::eLength;
}
}
NS_ABORT_IF_FALSE(size.mWidthType < nsStyleBackground::Size::eDimensionType_COUNT,
"bad width type");
NS_ABORT_IF_FALSE(size.mHeightType < nsStyleBackground::Size::eDimensionType_COUNT,
"bad height type");
NS_ABORT_IF_FALSE((size.mWidthType != nsStyleBackground::Size::eContain &&
size.mWidthType != nsStyleBackground::Size::eCover) ||
size.mWidthType == size.mHeightType,
"contain/cover apply to both dimensions or to neither");
}
};
template <class SpecifiedValueItem, class ComputedValueItem>
static void
SetBackgroundList(nsStyleContext* aStyleContext,
@ -4018,6 +4104,15 @@ nsRuleNode::ComputeBackgroundData(void* aStartStruct,
bg->mPositionCount, maxItemCount, rebuild,
canStoreInRuleTree);
// background-size: enum, length, auto, inherit, initial [pair list]
nsStyleBackground::Size initialSize;
initialSize.SetInitialValues();
SetBackgroundList(aContext, colorData.mBackSize, bg->mLayers,
parentBG->mLayers, &nsStyleBackground::Layer::mSize,
initialSize, parentBG->mSizeCount,
bg->mSizeCount, maxItemCount, rebuild,
canStoreInRuleTree);
if (rebuild) {
// Delete any extra items. We need to keep layers in which any
// property was specified.
@ -4036,6 +4131,8 @@ nsRuleNode::ComputeBackgroundData(void* aStartStruct,
bg->mOriginCount, fillCount);
FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mPosition,
bg->mPositionCount, fillCount);
FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mSize,
bg->mSizeCount, fillCount);
}
COMPUTE_END_RESET(Background, bg)
@ -5750,6 +5847,7 @@ nsRuleNode::HasAuthorSpecifiedRules(nsStyleContext* aStyleContext,
colorData.mBackPosition = nsnull;
colorData.mBackClip = nsnull;
colorData.mBackOrigin = nsnull;
colorData.mBackSize = nsnull;
if (ruleData.mLevel == nsStyleSet::eAgentSheet ||
ruleData.mLevel == nsStyleSet::eUserSheet) {

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

@ -1217,6 +1217,7 @@ nsStyleBackground::nsStyleBackground()
, mRepeatCount(1)
, mPositionCount(1)
, mImageCount(1)
, mSizeCount(1)
, mBackgroundColor(NS_RGBA(0, 0, 0, 0))
, mBackgroundInlinePolicy(NS_STYLE_BG_INLINE_POLICY_CONTINUOUS)
{
@ -1232,6 +1233,7 @@ nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource)
, mRepeatCount(aSource.mRepeatCount)
, mPositionCount(aSource.mPositionCount)
, mImageCount(aSource.mImageCount)
, mSizeCount(aSource.mSizeCount)
, mLayers(aSource.mLayers) // deep copy
, mBackgroundColor(aSource.mBackgroundColor)
, mBackgroundInlinePolicy(aSource.mBackgroundInlinePolicy)
@ -1246,6 +1248,7 @@ nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource)
mRepeatCount = PR_MAX(mRepeatCount, count);
mPositionCount = PR_MAX(mPositionCount, count);
mImageCount = PR_MAX(mImageCount, count);
mSizeCount = PR_MAX(mSizeCount, count);
}
}
@ -1303,6 +1306,46 @@ nsStyleBackground::Position::SetInitialValues()
mYIsPercent = PR_TRUE;
}
void
nsStyleBackground::Size::SetInitialValues()
{
mWidthType = mHeightType = eAuto;
}
PRBool
nsStyleBackground::Size::operator==(const Size& aOther) const
{
NS_ABORT_IF_FALSE(mWidthType < eDimensionType_COUNT,
"bad mWidthType for this");
NS_ABORT_IF_FALSE(mHeightType < eDimensionType_COUNT,
"bad mHeightType for this");
NS_ABORT_IF_FALSE(aOther.mWidthType < eDimensionType_COUNT,
"bad mWidthType for aOther");
NS_ABORT_IF_FALSE(aOther.mHeightType < eDimensionType_COUNT,
"bad mHeightType for aOther");
if (mWidthType != aOther.mWidthType || mHeightType != aOther.mHeightType)
return PR_FALSE;
if (mWidthType == ePercentage) {
if (mWidth.mFloat != aOther.mWidth.mFloat)
return PR_FALSE;
} else if (mWidthType == eLength) {
if (mWidth.mCoord != aOther.mWidth.mCoord)
return PR_FALSE;
}
if (mHeightType == ePercentage) {
if (mHeight.mFloat != aOther.mHeight.mFloat)
return PR_FALSE;
} else if (mHeightType == eLength) {
if (mHeight.mCoord != aOther.mHeight.mCoord)
return PR_FALSE;
}
return PR_TRUE;
}
nsStyleBackground::Layer::Layer()
{
}
@ -1319,6 +1362,7 @@ nsStyleBackground::Layer::SetInitialValues()
mOrigin = NS_STYLE_BG_ORIGIN_PADDING;
mRepeat = NS_STYLE_BG_REPEAT_XY;
mPosition.SetInitialValues();
mSize.SetInitialValues();
mImage = nsnull;
}
@ -1329,6 +1373,7 @@ PRBool nsStyleBackground::Layer::operator==(const Layer& aOther) const
mOrigin == aOther.mOrigin &&
mRepeat == aOther.mRepeat &&
mPosition == aOther.mPosition &&
mSize == aOther.mSize &&
EqualImages(mImage, aOther.mImage);
}

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

@ -194,6 +194,40 @@ struct nsStyleBackground {
}
};
struct Size;
friend struct Size;
struct Size {
typedef union {
nscoord mCoord; // for lengths
float mFloat; // for percents
} Dimension;
Dimension mWidth, mHeight;
enum DimensionType {
// If one of mWidth and mHeight is eContain or eCover, then both are.
// Also, these two values must equal the corresponding values in
// kBackgroundSizeKTable.
eContain, eCover,
eAuto,
ePercentage,
eLength,
eDimensionType_COUNT
};
PRUint8 mWidthType, mHeightType;
// Initialize nothing
Size() {}
// Initialize to initial values
void SetInitialValues();
PRBool operator==(const Size& aOther) const;
PRBool operator!=(const Size& aOther) const {
return !(*this == aOther);
}
};
struct Layer;
friend struct Layer;
struct Layer {
@ -203,6 +237,7 @@ struct nsStyleBackground {
PRUint8 mRepeat; // [reset] See nsStyleConsts.h
Position mPosition; // [reset]
nsCOMPtr<imgIRequest> mImage; // [reset]
Size mSize; // [reset]
// Initializes only mImage
Layer();
@ -225,7 +260,8 @@ struct nsStyleBackground {
mOriginCount,
mRepeatCount,
mPositionCount,
mImageCount;
mImageCount,
mSizeCount;
// Layers are stored in an array, matching the top-to-bottom order in
// which they are specified in CSS. The number of layers to be used
// should come from the background-image property. We create
@ -234,7 +270,7 @@ struct nsStyleBackground {
// callers in layout care about (which is also the one whose
// background-clip applies to the background-color) may not be last
// layer. In layers below the bottom layer, properties will be
// unitialized unless their count, above, indicates that they are
// uninitialized unless their count, above, indicates that they are
// present.
nsAutoTArray<Layer, 1> mLayers;

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

@ -100,6 +100,14 @@ var gCSSProperties = {
other_values: [ "border", "content", "border, padding", "padding, padding, padding", "border, border" ],
invalid_values: [ "margin", "padding padding" ]
},
"-moz-background-size": {
domProp: "MozBackgroundSize",
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ "auto", "auto auto" ],
other_values: [ "contain", "cover", "100px auto", "auto 100px", "100% auto", "auto 100%", "25% 50px", "3em 40%" ],
invalid_values: [ "contain contain", "cover cover", "cover auto", "auto cover", "contain cover", "cover contain", "-5px 3px", "3px -5px", "auto -5px", "-5px auto" ]
},
"-moz-binding": {
domProp: "MozBinding",
inherited: false,
@ -613,8 +621,8 @@ var gCSSProperties = {
domProp: "background",
inherited: false,
type: CSS_TYPE_TRUE_SHORTHAND,
subproperties: [ "background-attachment", "background-color", "background-image", "background-position", "background-repeat", "-moz-background-clip", "-moz-background-origin" ],
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"],
subproperties: [ "background-attachment", "background-color", "background-image", "background-position", "background-repeat", "-moz-background-clip", "-moz-background-origin", "-moz-background-size" ],
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%",