зеркало из https://github.com/mozilla/gecko-dev.git
Bug 769970 - Get SVG patterns working under HTML elements with CSS transforms applied. r=roc.
This commit is contained in:
Родитель
0a34a7ccc0
Коммит
d1a353d909
|
@ -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:
|
||||
|
|
Загрузка…
Ссылка в новой задаче