2017-10-27 20:33:53 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2004-11-23 16:51:57 +03:00
|
|
|
|
2017-08-27 21:08:26 +03:00
|
|
|
#include "nsSVGUseFrame.h"
|
|
|
|
|
2018-10-29 02:20:43 +03:00
|
|
|
#include "mozilla/dom/MutationEvent.h"
|
2013-01-17 00:50:58 +04:00
|
|
|
#include "mozilla/dom/SVGUseElement.h"
|
2017-08-30 16:14:46 +03:00
|
|
|
#include "SVGObserverUtils.h"
|
2004-11-23 16:51:57 +03:00
|
|
|
|
2018-03-22 21:20:41 +03:00
|
|
|
using namespace mozilla;
|
2013-01-17 00:50:58 +04:00
|
|
|
using namespace mozilla::dom;
|
|
|
|
|
2004-11-23 16:51:57 +03:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Implementation
|
|
|
|
|
2018-03-22 21:20:41 +03:00
|
|
|
nsIFrame* NS_NewSVGUseFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle) {
|
|
|
|
return new (aPresShell) nsSVGUseFrame(aStyle);
|
2004-11-23 16:51:57 +03:00
|
|
|
}
|
|
|
|
|
2009-09-12 20:49:24 +04:00
|
|
|
NS_IMPL_FRAMEARENA_HELPERS(nsSVGUseFrame)
|
|
|
|
|
2006-03-02 23:22:19 +03:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsIFrame methods:
|
|
|
|
|
2014-05-25 02:20:40 +04:00
|
|
|
void nsSVGUseFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
|
|
|
|
nsIFrame* aPrevInFlow) {
|
2015-03-03 14:08:59 +03:00
|
|
|
NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::use),
|
2013-01-08 07:22:41 +04:00
|
|
|
"Content is not an SVG use!");
|
2012-03-03 13:21:09 +04:00
|
|
|
|
|
|
|
mHasValidDimensions =
|
2013-01-17 00:50:58 +04:00
|
|
|
static_cast<SVGUseElement*>(aContent)->HasValidDimensions();
|
2009-01-19 21:31:34 +03:00
|
|
|
|
2016-04-18 10:46:09 +03:00
|
|
|
nsSVGGFrame::Init(aContent, aParent, aPrevInFlow);
|
2009-01-19 21:31:34 +03:00
|
|
|
}
|
|
|
|
|
2018-10-29 02:20:43 +03:00
|
|
|
nsresult nsSVGUseFrame::AttributeChanged(int32_t aNamespaceID,
|
2018-07-16 17:07:58 +03:00
|
|
|
nsAtom* aAttribute, int32_t aModType) {
|
2018-10-29 02:20:43 +03:00
|
|
|
// Currently our SMIL implementation does not modify the DOM attributes. Once
|
|
|
|
// we implement the SVG 2 SMIL behaviour this can be removed
|
|
|
|
// SVGUseElement::AfterSetAttr's implementation will be sufficient.
|
|
|
|
if (aModType == MutationEvent_Binding::SMIL) {
|
|
|
|
auto* content = SVGUseElement::FromNode(GetContent());
|
|
|
|
content->ProcessAttributeChange(aNamespaceID, aAttribute);
|
2016-07-05 11:37:17 +03:00
|
|
|
}
|
|
|
|
|
2018-10-29 02:20:43 +03:00
|
|
|
return nsSVGGFrame::AttributeChanged(aNamespaceID, aAttribute, aModType);
|
|
|
|
}
|
|
|
|
|
|
|
|
void nsSVGUseFrame::PositionAttributeChanged() {
|
|
|
|
// make sure our cached transform matrix gets (lazily) updated
|
|
|
|
mCanvasTM = nullptr;
|
|
|
|
nsLayoutUtils::PostRestyleEvent(GetContent()->AsElement(), nsRestyleHint(0),
|
|
|
|
nsChangeHint_InvalidateRenderingObservers);
|
|
|
|
nsSVGUtils::ScheduleReflowSVG(this);
|
|
|
|
nsSVGUtils::NotifyChildrenOfSVGChange(this, TRANSFORM_CHANGED);
|
|
|
|
}
|
|
|
|
|
|
|
|
void nsSVGUseFrame::DimensionAttributeChanged(bool aHadValidDimensions,
|
|
|
|
bool aAttributeIsUsed) {
|
|
|
|
bool invalidate = aAttributeIsUsed;
|
|
|
|
if (mHasValidDimensions != aHadValidDimensions) {
|
|
|
|
mHasValidDimensions = !mHasValidDimensions;
|
|
|
|
invalidate = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (invalidate) {
|
|
|
|
nsLayoutUtils::PostRestyleEvent(GetContent()->AsElement(), nsRestyleHint(0),
|
2014-11-06 12:30:11 +03:00
|
|
|
nsChangeHint_InvalidateRenderingObservers);
|
2012-11-28 13:42:13 +04:00
|
|
|
nsSVGUtils::ScheduleReflowSVG(this);
|
2006-03-02 23:22:19 +03:00
|
|
|
}
|
2018-10-29 02:20:43 +03:00
|
|
|
}
|
2006-03-02 23:22:19 +03:00
|
|
|
|
2018-10-29 02:20:43 +03:00
|
|
|
void nsSVGUseFrame::HrefChanged() {
|
|
|
|
nsLayoutUtils::PostRestyleEvent(GetContent()->AsElement(), nsRestyleHint(0),
|
|
|
|
nsChangeHint_InvalidateRenderingObservers);
|
|
|
|
nsSVGUtils::ScheduleReflowSVG(this);
|
2006-03-02 23:22:19 +03:00
|
|
|
}
|
|
|
|
|
2012-02-01 20:25:44 +04:00
|
|
|
//----------------------------------------------------------------------
|
2017-02-09 21:24:31 +03:00
|
|
|
// nsSVGDisplayableFrame methods
|
2012-02-01 20:25:44 +04:00
|
|
|
|
2012-07-22 04:01:44 +04:00
|
|
|
void nsSVGUseFrame::ReflowSVG() {
|
2012-05-17 08:05:09 +04:00
|
|
|
// We only handle x/y offset here, since any width/height that is in force is
|
|
|
|
// handled by the nsSVGOuterSVGFrame for the anonymous <svg> that will be
|
|
|
|
// created for that purpose.
|
|
|
|
float x, y;
|
2017-08-27 01:58:38 +03:00
|
|
|
static_cast<SVGUseElement*>(GetContent())
|
2012-07-30 18:20:58 +04:00
|
|
|
->GetAnimatedLengthValues(&x, &y, nullptr);
|
2012-05-17 08:05:09 +04:00
|
|
|
mRect.MoveTo(nsLayoutUtils::RoundGfxRectToAppRect(gfxRect(x, y, 0.0, 0.0),
|
2018-08-11 07:46:23 +03:00
|
|
|
AppUnitsPerCSSPixel())
|
|
|
|
.TopLeft());
|
Bug 997735 - Invalidate when reflowing SVG containers. r=roc
Without this patch, when changing the x/y attributes of svg:use, innerSVG and foreignObject, we were relying on the transform changes of the children to trigger the right invalidations. However, changes to those attributes can also change the filter region. And there's a difference between moving children in a fixed filter region and moving the filter region along with the children: In the first case, we wouldn't need to invalidate anything outside the old filter region, because those parts of the children would be clipped away anyway. But when the filter region changes, we need to invalidate both the old and the new filter region. Also, when the filter has primitives without inputs, e.g. flood or turbulence, the filtered frame needs to be invalidate even if it has no children.
2014-04-23 13:48:07 +04:00
|
|
|
|
|
|
|
// If we have a filter, we need to invalidate ourselves because filter
|
|
|
|
// output can change even if none of our descendants need repainting.
|
2016-04-12 08:52:43 +03:00
|
|
|
if (StyleEffects()->HasFilters()) {
|
Bug 997735 - Invalidate when reflowing SVG containers. r=roc
Without this patch, when changing the x/y attributes of svg:use, innerSVG and foreignObject, we were relying on the transform changes of the children to trigger the right invalidations. However, changes to those attributes can also change the filter region. And there's a difference between moving children in a fixed filter region and moving the filter region along with the children: In the first case, we wouldn't need to invalidate anything outside the old filter region, because those parts of the children would be clipped away anyway. But when the filter region changes, we need to invalidate both the old and the new filter region. Also, when the filter has primitives without inputs, e.g. flood or turbulence, the filtered frame needs to be invalidate even if it has no children.
2014-04-23 13:48:07 +04:00
|
|
|
InvalidateFrame();
|
|
|
|
}
|
|
|
|
|
2016-04-18 10:46:09 +03:00
|
|
|
nsSVGGFrame::ReflowSVG();
|
2012-05-17 08:05:09 +04:00
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
void nsSVGUseFrame::NotifySVGChanged(uint32_t aFlags) {
|
2012-02-01 20:25:44 +04:00
|
|
|
if (aFlags & COORD_CONTEXT_CHANGED && !(aFlags & TRANSFORM_CHANGED)) {
|
|
|
|
// Coordinate context changes affect mCanvasTM if we have a
|
|
|
|
// percentage 'x' or 'y'
|
2017-08-27 01:58:38 +03:00
|
|
|
SVGUseElement* use = static_cast<SVGUseElement*>(GetContent());
|
2013-01-17 00:50:59 +04:00
|
|
|
if (use->mLengthAttributes[SVGUseElement::ATTR_X].IsPercentage() ||
|
|
|
|
use->mLengthAttributes[SVGUseElement::ATTR_Y].IsPercentage()) {
|
2012-02-01 20:25:44 +04:00
|
|
|
aFlags |= TRANSFORM_CHANGED;
|
2012-06-23 20:36:46 +04:00
|
|
|
// Ancestor changes can't affect how we render from the perspective of
|
|
|
|
// any rendering observers that we may have, so we don't need to
|
|
|
|
// invalidate them. We also don't need to invalidate ourself, since our
|
|
|
|
// changed ancestor will have invalidated its entire area, which includes
|
|
|
|
// our area.
|
|
|
|
// For perf reasons we call this before calling NotifySVGChanged() below.
|
2012-07-22 04:01:44 +04:00
|
|
|
nsSVGUtils::ScheduleReflowSVG(this);
|
2012-02-01 20:25:44 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-19 17:50:07 +04:00
|
|
|
// We don't remove the TRANSFORM_CHANGED flag here if we have a viewBox or
|
|
|
|
// non-percentage width/height, since if they're set then they are cloned to
|
|
|
|
// an anonymous child <svg>, and its nsSVGInnerSVGFrame will do that.
|
|
|
|
|
2016-04-18 10:46:09 +03:00
|
|
|
nsSVGGFrame::NotifySVGChanged(aFlags);
|
2012-02-01 20:25:44 +04:00
|
|
|
}
|