Bug 769970 - Get SVG patterns working under HTML elements with CSS transforms applied. r=roc.

This commit is contained in:
Jonathan Watt 2012-07-14 00:18:38 +01:00
Родитель 0a34a7ccc0
Коммит d1a353d909
11 изменённых файлов: 131 добавлений и 22 удалений

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

@ -0,0 +1,47 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test SVG patterning under transformed HTML elements</title>
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=769970 -->
<style type="text/css">
* { margin: 0; border: 0; padding: 0;}
svg {
display: block;
position: absolute;
}
.scaled {
left: 1px;
top: 1px;
width: 3px;
height: 3px;
transform: scale(100,100);
transform-origin: 0 0;
}
</style>
</head>
<body bgcolor="lime">
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
<circle cx="151" cy="151" r="148" fill="red"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" class="scaled">
<pattern id="redDot" width="1" height="1">
<circle cx="1.5" cy="1.5" r="1.48" fill="red"/>
</pattern>
<pattern id="limeDot" width="1" height="1">
<circle cx="1.5" cy="1.5" r="1.5" fill="lime"/>
</pattern>
<rect width="100%" height="100%" fill="url(#redDot)"/>
<rect width="100%" height="100%" fill="url(#limeDot)"/>
</svg>
</body>
</html>

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

@ -0,0 +1,47 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test SVG patterning under transformed HTML elements</title>
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=769970 -->
<style type="text/css">
* { margin: 0; border: 0; padding: 0;}
svg {
display: block;
position: absolute;
}
.scaled {
left: 50px;
top: 50px;
width: 150px;
height: 150px;
transform: scale(2,2);
transform-origin: 0 0;
}
</style>
</head>
<body bgcolor="lime">
<svg xmlns="http://www.w3.org/2000/svg" width="350" height="350">
<circle cx="200" cy="200" r="147" fill="red"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" class="scaled">
<pattern id="redDot" width="1" height="1">
<circle cx="75" cy="75" r="74" fill="red"/>
</pattern>
<pattern id="limeDot" width="1" height="1">
<circle cx="75" cy="75" r="75" fill="lime"/>
</pattern>
<rect width="100%" height="100%" fill="url(#redDot)"/>
<rect width="100%" height="100%" fill="url(#limeDot)"/>
</svg>
</body>
</html>

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

@ -29,5 +29,6 @@
== mask-html-xbl-bound-01.html mask-html-01-ref.svg
== mask-transformed-html-01.xhtml ../pass.svg
== mask-transformed-html-02.xhtml ../pass.svg
== patterned-svg-under-transformed-html-01.xhtml ../pass.svg
== patterned-svg-under-transformed-html-02.xhtml ../pass.svg

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

@ -898,7 +898,9 @@ nsSVGGlyphFrame::SetupCairoState(gfxContext *aContext, gfxPattern **aStrokePatte
if (ps) {
// Gradient or Pattern: can get pattern directly from frame
strokePattern = ps->GetPaintServerPattern(this, &nsStyleSVG::mStroke, opacity);
strokePattern =
ps->GetPaintServerPattern(this, aContext->CurrentMatrix(),
&nsStyleSVG::mStroke, opacity);
}
if (!strokePattern) {

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

@ -238,6 +238,7 @@ nsSVGGradientFrame::GetRadialGradientWithLength(PRUint32 aIndex,
already_AddRefed<gfxPattern>
nsSVGGradientFrame::GetPaintServerPattern(nsIFrame *aSource,
const gfxMatrix& aContextMatrix,
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
float aGraphicOpacity,
const gfxRect *aOverrideBounds)

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

@ -44,6 +44,7 @@ public:
// nsSVGPaintServerFrame methods:
virtual already_AddRefed<gfxPattern>
GetPaintServerPattern(nsIFrame *aSource,
const gfxMatrix& aContextMatrix,
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
float aGraphicOpacity,
const gfxRect *aOverrideBounds);

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

@ -590,7 +590,8 @@ static already_AddRefed<gfxDrawable>
DrawableFromPaintServer(nsIFrame* aFrame,
nsIFrame* aTarget,
const nsSize& aPaintServerSize,
const gfxIntSize& aRenderSize)
const gfxIntSize& aRenderSize,
const gfxMatrix& aContextMatrix)
{
// aPaintServerSize is the size that would be filled when using
// background-repeat:no-repeat and background-size:auto. For normal background
@ -609,7 +610,8 @@ DrawableFromPaintServer(nsIFrame* aFrame,
aPaintServerSize.width, aPaintServerSize.height);
overrideBounds.ScaleInverse(aFrame->PresContext()->AppUnitsPerDevPixel());
nsRefPtr<gfxPattern> pattern =
server->GetPaintServerPattern(aTarget, &nsStyleSVG::mFill, 1.0, &overrideBounds);
server->GetPaintServerPattern(aTarget, aContextMatrix,
&nsStyleSVG::mFill, 1.0, &overrideBounds);
if (!pattern)
return nsnull;
@ -655,7 +657,8 @@ nsSVGIntegrationUtils::DrawPaintServer(nsRenderingContext* aRenderingContext,
nsIntSize roundedOut = destSize.ToOutsidePixels(appUnitsPerDevPixel).Size();
gfxIntSize imageSize(roundedOut.width, roundedOut.height);
nsRefPtr<gfxDrawable> drawable =
DrawableFromPaintServer(aPaintServer, aTarget, aPaintServerSize, imageSize);
DrawableFromPaintServer(aPaintServer, aTarget, aPaintServerSize, imageSize,
aRenderingContext->ThebesContext()->CurrentMatrix());
if (drawable) {
nsLayoutUtils::DrawPixelSnapped(aRenderingContext, drawable, aFilter,

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

@ -18,7 +18,9 @@ nsSVGPaintServerFrame::SetupPaintServer(gfxContext *aContext,
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
float aOpacity)
{
nsRefPtr<gfxPattern> pattern = GetPaintServerPattern(aSource, aFillOrStroke, aOpacity);
nsRefPtr<gfxPattern> pattern =
GetPaintServerPattern(aSource, aContext->CurrentMatrix(), aFillOrStroke,
aOpacity);
if (!pattern)
return false;

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

@ -36,9 +36,15 @@ public:
/**
* Constructs a gfxPattern of the paint server rendering.
*
* @param aContextMatrix The transform matrix that is currently applied to
* the gfxContext that is being drawn to. This is needed by SVG patterns so
* that surfaces of the correct size can be created. (SVG gradients are
* vector based, so it's not used there.)
*/
virtual already_AddRefed<gfxPattern>
GetPaintServerPattern(nsIFrame *aSource,
const gfxMatrix& aContextMatrix,
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
float aOpacity,
const gfxRect *aOverrideBounds = nsnull) = 0;

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

@ -144,6 +144,7 @@ nsSVGPatternFrame::GetCanvasTM(PRUint32 aFor)
nsresult
nsSVGPatternFrame::PaintPattern(gfxASurface** surface,
gfxMatrix* patternMatrix,
const gfxMatrix &aContextMatrix,
nsIFrame *aSource,
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
float aGraphicOpacity,
@ -189,16 +190,15 @@ nsSVGPatternFrame::PaintPattern(gfxASurface** surface,
// Get all of the information we need from our "caller" -- i.e.
// the geometry that is being rendered with a pattern
gfxRect callerBBox;
gfxMatrix callerCTM;
if (NS_FAILED(GetTargetGeometry(&callerCTM,
&callerBBox,
if (NS_FAILED(GetTargetGeometry(&callerBBox,
aSource,
aContextMatrix,
aOverrideBounds)))
return NS_ERROR_FAILURE;
// Construct the CTM that we will provide to our children when we
// render them into the tile.
gfxMatrix ctm = ConstructCTM(callerBBox, callerCTM, aSource);
gfxMatrix ctm = ConstructCTM(callerBBox, aContextMatrix, aSource);
if (ctm.IsSingular()) {
return NS_ERROR_FAILURE;
}
@ -215,7 +215,7 @@ nsSVGPatternFrame::PaintPattern(gfxASurface** surface,
// Get the bounding box of the pattern. This will be used to determine
// the size of the surface, and will also be used to define the bounding
// box for the pattern tile.
gfxRect bbox = GetPatternRect(callerBBox, callerCTM, aSource);
gfxRect bbox = GetPatternRect(callerBBox, aContextMatrix, aSource);
// Get the pattern transform
gfxMatrix patternTransform = GetPatternTransform();
@ -228,7 +228,7 @@ nsSVGPatternFrame::PaintPattern(gfxASurface** surface,
// Get the transformation matrix that we will hand to the renderer's pattern
// routine.
*patternMatrix = GetPatternMatrix(patternTransform,
bbox, callerBBox, callerCTM);
bbox, callerBBox, aContextMatrix);
// Now that we have all of the necessary geometries, we can
// create our surface.
@ -621,9 +621,9 @@ nsSVGPatternFrame::GetPatternMatrix(const gfxMatrix &patternTransform,
}
nsresult
nsSVGPatternFrame::GetTargetGeometry(gfxMatrix *aCTM,
gfxRect *aBBox,
nsSVGPatternFrame::GetTargetGeometry(gfxRect *aBBox,
nsIFrame *aTarget,
const gfxMatrix &aContextMatrix,
const gfxRect *aOverrideBounds)
{
*aBBox = aOverrideBounds ? *aOverrideBounds : nsSVGUtils::GetBBox(aTarget);
@ -635,14 +635,10 @@ nsSVGPatternFrame::GetTargetGeometry(gfxMatrix *aCTM,
return NS_ERROR_FAILURE;
}
}
// Get the transformation matrix from our calling geometry
*aCTM = nsSVGUtils::GetCanvasTM(aTarget, nsISVGChildFrame::FOR_PAINTING);
// OK, now fix up the bounding box to reflect user coordinates
// We handle device unit scaling in pattern matrix
{
float scale = nsSVGUtils::MaxExpansion(*aCTM);
float scale = nsSVGUtils::MaxExpansion(aContextMatrix);
if (scale <= 0) {
return NS_ERROR_FAILURE;
}
@ -656,6 +652,7 @@ nsSVGPatternFrame::GetTargetGeometry(gfxMatrix *aCTM,
already_AddRefed<gfxPattern>
nsSVGPatternFrame::GetPaintServerPattern(nsIFrame *aSource,
const gfxMatrix& aContextMatrix,
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
float aGraphicOpacity,
const gfxRect *aOverrideBounds)
@ -668,7 +665,7 @@ nsSVGPatternFrame::GetPaintServerPattern(nsIFrame *aSource,
// Paint it!
nsRefPtr<gfxASurface> surface;
gfxMatrix pMatrix;
nsresult rv = PaintPattern(getter_AddRefs(surface), &pMatrix,
nsresult rv = PaintPattern(getter_AddRefs(surface), &pMatrix, aContextMatrix,
aSource, aFillOrStroke, aGraphicOpacity, aOverrideBounds);
if (NS_FAILED(rv)) {

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

@ -40,6 +40,7 @@ public:
// nsSVGPaintServerFrame methods:
virtual already_AddRefed<gfxPattern>
GetPaintServerPattern(nsIFrame *aSource,
const gfxMatrix& aContextMatrix,
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
float aOpacity,
const gfxRect *aOverrideBounds);
@ -108,6 +109,7 @@ protected:
nsresult PaintPattern(gfxASurface **surface,
gfxMatrix *patternMatrix,
const gfxMatrix &aContextMatrix,
nsIFrame *aSource,
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
float aGraphicOpacity,
@ -123,9 +125,9 @@ protected:
gfxMatrix ConstructCTM(const gfxRect &callerBBox,
const gfxMatrix &callerCTM,
nsIFrame *aTarget);
nsresult GetTargetGeometry(gfxMatrix *aCTM,
gfxRect *aBBox,
nsresult GetTargetGeometry(gfxRect *aBBox,
nsIFrame *aTarget,
const gfxMatrix &aContextMatrix,
const gfxRect *aOverrideBounds);
private: