SVG placement misaligned.

This commit is contained in:
Fedor 2019-09-05 20:09:38 +03:00
parent 1f57f45f54
commit c0a23f0579
8 changed files with 122 additions and 35 deletions

View File

@ -112,6 +112,18 @@ public:
_31 == 0.0 && _32 == 0.0;
}
/* Returns true if the matrix is a rectilinear transformation (i.e.
* grid-aligned rectangles are transformed to grid-aligned rectangles)
*/
bool IsRectilinear() const {
if (FuzzyEqual(_12, 0) && FuzzyEqual(_21, 0)) {
return true;
} else if (FuzzyEqual(_22, 0) && FuzzyEqual(_11, 0)) {
return true;
}
return false;
}
/**
* Inverts this matrix, if possible. Otherwise, the matrix is left
* unchanged.

View File

@ -5708,7 +5708,7 @@ nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame,
}
/* Allows us to access dimension getters by index. */
float coords[2];
float transformOrigin[2];
TransformReferenceBox::DimensionGetter dimensionGetter[] =
{ &TransformReferenceBox::Width, &TransformReferenceBox::Height };
TransformReferenceBox::DimensionGetter offsetGetter[] =
@ -5718,33 +5718,33 @@ nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame,
/* If the transform-origin specifies a percentage, take the percentage
* of the size of the box.
*/
const nsStyleCoord &coord = display->mTransformOrigin[index];
if (coord.GetUnit() == eStyleUnit_Calc) {
const nsStyleCoord::Calc *calc = coord.GetCalcValue();
coords[index] =
const nsStyleCoord &originValue = display->mTransformOrigin[index];
if (originValue.GetUnit() == eStyleUnit_Calc) {
const nsStyleCoord::Calc *calc = originValue.GetCalcValue();
transformOrigin[index] =
NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) *
calc->mPercent +
NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
} else if (coord.GetUnit() == eStyleUnit_Percent) {
coords[index] =
} else if (originValue.GetUnit() == eStyleUnit_Percent) {
transformOrigin[index] =
NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) *
coord.GetPercentValue();
originValue.GetPercentValue();
} else {
MOZ_ASSERT(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
coords[index] =
NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel);
MOZ_ASSERT(originValue.GetUnit() == eStyleUnit_Coord, "unexpected unit");
transformOrigin[index] =
NSAppUnitsToFloatPixels(originValue.GetCoordValue(), aAppUnitsPerPixel);
}
if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
// SVG frames (unlike other frames) have a reference box that can be (and
// typically is) offset from the TopLeft() of the frame. We need to
// account for that here.
coords[index] +=
transformOrigin[index] +=
NSAppUnitsToFloatPixels((refBox.*offsetGetter[index])(), aAppUnitsPerPixel);
}
}
return Point3D(coords[0], coords[1],
return Point3D(transformOrigin[0], transformOrigin[1],
NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(),
aAppUnitsPerPixel));
}
@ -5917,6 +5917,17 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
frame && frame->IsSVGTransformed(&svgTransform, &transformFromSVGParent);
bool hasTransformFromSVGParent =
hasSVGTransforms && !transformFromSVGParent.IsIdentity();
bool shouldRound = true;
// An SVG frame should not have its translation rounded.
// Note it's possible that the SVG frame doesn't have an SVG
// transform but only has a CSS transform.
if (frame && frame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT) &&
!(frame->GetType() == nsGkAtoms::svgOuterSVGAnonChildFrame)) {
shouldRound = false;
}
/* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */
if (aProperties.mTransformList) {
result = nsStyleTransformMatrix::ReadTransforms(aProperties.mTransformList->mHead,
@ -5994,7 +6005,7 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
// Otherwise we need to manually translate into our parent's coordinate
// space.
if (frame->IsTransformed()) {
nsLayoutUtils::PostTranslate(result, frame->GetPosition(), aAppUnitsPerPixel, !hasSVGTransforms);
nsLayoutUtils::PostTranslate(result, frame->GetPosition(), aAppUnitsPerPixel, shouldRound);
}
Matrix4x4 parent =
GetResultingTransformMatrixInternal(props,
@ -6005,7 +6016,7 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
}
if (aFlags & OFFSET_BY_ORIGIN) {
nsLayoutUtils::PostTranslate(result, aOrigin, aAppUnitsPerPixel, !hasSVGTransforms);
nsLayoutUtils::PostTranslate(result, aOrigin, aAppUnitsPerPixel, shouldRound);
}
return result;

View File

@ -0,0 +1,10 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<style>
</style>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<rect id="a" x="0.49" y="0.51" width="2.5" height="2.5"/>
<rect id="b" x="3.5" y="3.5" width="2.5" height="2.5"/>
</svg>

View File

@ -0,0 +1,13 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<style>
#a {
transform: scaleY(1);
}
</style>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<rect id="a" x="0.49" y="0.51" width="2.5" height="2.5"/>
<rect id="b" x="3.5" y="3.5" width="2.5" height="2.5"/>
</svg>

View File

@ -140,6 +140,7 @@ random == dynamic-use-nested-01b.svg dynamic-use-nested-01-ref.svg
== fragmentIdentifier-01.xhtml pass.svg
== linked-filter-01.svg pass.svg
== linked-pattern-01.svg pass.svg
pref(layout.css.devPixelsPerPx,"1.0") == svg-blurry-with-subpixel-position.html svg-blurry-with-subpixel-position-ref.html
== use-01.svg pass.svg
== use-01-extref.svg pass.svg
== use-02-extref.svg use-02-extref-ref.svg
@ -371,6 +372,7 @@ fuzzy-if(skiaContent,1,610) == textPath-03.svg pass.svg
== text-white-space-01.svg text-white-space-01-ref.svg
== thin-stroke-01.svg pass.svg
== zero-stroke-01.svg pass.svg
== css-transform-svg.html css-transform-svg-ref.html
== tspan-dxdy-01.svg tspan-dxdy-ref.svg
== tspan-dxdy-02.svg tspan-dxdy-ref.svg
== tspan-dxdy-03.svg tspan-dxdy-ref.svg

View File

@ -0,0 +1,13 @@
<!doctype html>
<style>
svg {
width:750px;
height:750px;
margin:3px;
}
</style>
<svg viewBox="0.5 0.5 750 750">
<path d="M3,6L277,6M3,12L277,12M3,18L277,18M3,24L277,24M3,30L277,30M3,36L277,36M3,42L277,42M3,48L277,48M3,54L277,54M3,60L277,60M3,66L277,66M3,72L277,72M3,78L277,78M3,84L277,84M3,90L277,90M3,96L277,96M3,102L277,102M3,108L277,108M3,114L277,114" style="stroke-width:1; stroke:black;" />
<path d="M6,3L6,277M12,3L12,277M18,3L18,277M24,3L24,277M30,3L30,277M36,3L36,277M42,3L42,277M48,3L48,277M54,3L54,277M60,3L60,277M66,3L66,277M72,3L72,277M78,3L78,277M84,3L84,277M90,3L90,277M96,3L96,277M102,3L102,277M108,3L108,277M114,3L114,277" style="stroke-width:1; stroke:black;" />
</svg>

View File

@ -0,0 +1,13 @@
<!doctype html>
<style>
svg {
width:750px;
height:750px;
margin:2.5px;
}
</style>
<svg viewBox="0.5 0.5 750 750">
<path d="M3,6L277,6M3,12L277,12M3,18L277,18M3,24L277,24M3,30L277,30M3,36L277,36M3,42L277,42M3,48L277,48M3,54L277,54M3,60L277,60M3,66L277,66M3,72L277,72M3,78L277,78M3,84L277,84M3,90L277,90M3,96L277,96M3,102L277,102M3,108L277,108M3,114L277,114" style="stroke-width:1; stroke:black;" />
<path d="M6,3L6,277M12,3L12,277M18,3L18,277M24,3L24,277M30,3L30,277M36,3L36,277M42,3L42,277M48,3L48,277M54,3L54,277M60,3L60,277M66,3L66,277M72,3L72,277M78,3L78,277M84,3L84,277M90,3L90,277M96,3L96,277M102,3L102,277M108,3L108,277M114,3L114,277" style="stroke-width:1; stroke:black;" />
</svg>

View File

@ -979,43 +979,56 @@ nsSVGOuterSVGAnonChildFrame::GetType() const
return nsGkAtoms::svgOuterSVGAnonChildFrame;
}
bool
nsSVGOuterSVGAnonChildFrame::IsSVGTransformed(Matrix* aOwnTransform,
Matrix* aFromParentTransform) const
static Matrix
ComputeOuterSVGAnonChildFrameTransform(const nsSVGOuterSVGAnonChildFrame* aFrame)
{
// Our elements 'transform' attribute is applied to our nsSVGOuterSVGFrame
// parent, and the element's children-only transforms are applied to us, the
// anonymous child frame. Since we are the child frame, we apply the
// children-only transforms as if they are our own transform.
SVGSVGElement* content = static_cast<SVGSVGElement*>(mContent);
SVGSVGElement* content = static_cast<SVGSVGElement*>(aFrame->GetContent());
if (!content->HasChildrenOnlyTransform()) {
return false;
return Matrix();
}
// Outer-<svg> doesn't use x/y, so we can pass eChildToUserSpace here.
gfxMatrix ownMatrix =
content->PrependLocalTransformsTo(gfxMatrix(), eChildToUserSpace);
if (ownMatrix.IsIdentity()) {
return false;
if (ownMatrix.HasNonTranslation()) {
// viewBox, currentScale and currentTranslate should only produce a
// rectilinear transform.
MOZ_ASSERT(ownMatrix.IsRectilinear(),
"Non-rectilinear transform will break the following logic");
// The nsDisplayTransform code will apply this transform to our frame,
// including to our frame position. We don't want our frame position to
// be scaled though, so we need to correct for that in the transform.
CSSPoint pos = CSSPixel::FromAppUnits(aFrame->GetPosition());
CSSPoint scaledPos = CSSPoint(ownMatrix._11 * pos.x, ownMatrix._22 * pos.y);
CSSPoint deltaPos = scaledPos - pos;
ownMatrix *= gfxMatrix::Translation(-deltaPos.x, -deltaPos.y);
}
if (aOwnTransform) {
if (ownMatrix.HasNonTranslation()) {
// Note: viewBox, currentScale and currentTranslate should only
// produce a rectilinear transform.
// The nsDisplayTransform code will apply this transform to our frame,
// including to our frame position. We don't want our frame position to
// be scaled though, so we need to correct for that in the transform.
CSSPoint pos = CSSPixel::FromAppUnits(GetPosition());
CSSPoint scaledPos = CSSPoint(ownMatrix._11 * pos.x, ownMatrix._22 * pos.y);
CSSPoint deltaPos = scaledPos - pos;
ownMatrix *= gfxMatrix::Translation(-deltaPos.x, -deltaPos.y);
}
return gfx::ToMatrix(ownMatrix);
}
*aOwnTransform = gfx::ToMatrix(ownMatrix);
// We want this frame to be a reference frame. An easy way to achieve that is
// to always return true from this method, even for identity transforms.
// This frame being a reference frame ensures that the offset between this
// <svg> element and the parent reference frame is completely absorbed by the
// nsDisplayTransform that's created for this frame, and that this offset does
// not affect our descendants' transforms. Consequently, if the <svg> element
// moves, e.g. during scrolling, the transform matrices of our contents are
// unaffected. This simplifies invalidation.
bool
nsSVGOuterSVGAnonChildFrame::IsSVGTransformed(Matrix* aOwnTransform,
Matrix* aFromParentTransform) const
{
if (aOwnTransform) {
*aOwnTransform = ComputeOuterSVGAnonChildFrameTransform(this);
}
return true;