2004-11-23 16:51:57 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
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
|
|
|
|
2012-03-26 15:58:59 +04:00
|
|
|
// Keep in (case-insensitive) order:
|
2004-11-23 16:51:57 +03:00
|
|
|
#include "nsIAnonymousContentCreator.h"
|
2013-04-25 13:18:42 +04:00
|
|
|
#include "nsSVGEffects.h"
|
2012-03-26 15:58:59 +04:00
|
|
|
#include "nsSVGGFrame.h"
|
2013-01-17 00:50:58 +04:00
|
|
|
#include "mozilla/dom/SVGUseElement.h"
|
2012-09-06 00:49:53 +04:00
|
|
|
#include "nsContentList.h"
|
2004-11-23 16:51:57 +03:00
|
|
|
|
2013-01-17 00:50:58 +04:00
|
|
|
using namespace mozilla::dom;
|
|
|
|
|
2017-04-30 18:30:08 +03:00
|
|
|
class nsSVGUseFrame final
|
|
|
|
: public nsSVGGFrame
|
|
|
|
, public nsIAnonymousContentCreator
|
2004-11-23 16:51:57 +03:00
|
|
|
{
|
2005-11-11 05:36:29 +03:00
|
|
|
friend nsIFrame*
|
2009-01-19 21:31:34 +03:00
|
|
|
NS_NewSVGUseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
|
2004-11-23 16:51:57 +03:00
|
|
|
|
|
|
|
protected:
|
2016-04-18 10:46:09 +03:00
|
|
|
explicit nsSVGUseFrame(nsStyleContext* aContext)
|
2017-05-26 13:11:11 +03:00
|
|
|
: nsSVGGFrame(aContext, kClassID)
|
2016-04-18 10:46:09 +03:00
|
|
|
, mHasValidDimensions(true)
|
2012-03-03 13:21:09 +04:00
|
|
|
{}
|
2004-11-23 16:51:57 +03:00
|
|
|
|
2009-01-09 19:35:24 +03:00
|
|
|
public:
|
2009-01-12 22:20:59 +03:00
|
|
|
NS_DECL_QUERYFRAME
|
2017-05-26 13:11:11 +03:00
|
|
|
NS_DECL_FRAMEARENA_HELPERS(nsSVGUseFrame)
|
2009-01-12 22:20:59 +03:00
|
|
|
|
2006-03-02 23:22:19 +03:00
|
|
|
// nsIFrame interface:
|
2014-05-25 02:20:40 +04:00
|
|
|
virtual void Init(nsIContent* aContent,
|
|
|
|
nsContainerFrame* aParent,
|
2015-03-21 19:28:04 +03:00
|
|
|
nsIFrame* aPrevInFlow) override;
|
2009-01-19 21:31:34 +03:00
|
|
|
|
2014-02-18 11:47:48 +04:00
|
|
|
virtual nsresult AttributeChanged(int32_t aNameSpaceID,
|
2014-02-18 12:36:33 +04:00
|
|
|
nsIAtom* aAttribute,
|
2015-03-21 19:28:04 +03:00
|
|
|
int32_t aModType) override;
|
2004-11-23 16:51:57 +03:00
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
|
2007-02-18 20:34:09 +03:00
|
|
|
|
2014-01-06 03:31:14 +04:00
|
|
|
#ifdef DEBUG_FRAME_DUMP
|
2015-03-21 19:28:04 +03:00
|
|
|
virtual nsresult GetFrameName(nsAString& aResult) const override
|
2005-04-01 23:56:08 +04:00
|
|
|
{
|
|
|
|
return MakeFrameName(NS_LITERAL_STRING("SVGUse"), aResult);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-02-09 21:24:31 +03:00
|
|
|
// nsSVGDisplayableFrame interface:
|
2015-03-21 19:28:04 +03:00
|
|
|
virtual void ReflowSVG() override;
|
|
|
|
virtual void NotifySVGChanged(uint32_t aFlags) override;
|
2012-02-01 20:25:44 +04:00
|
|
|
|
2004-11-23 16:51:57 +03:00
|
|
|
// nsIAnonymousContentCreator
|
2015-03-21 19:28:04 +03:00
|
|
|
virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
|
2014-07-16 22:41:57 +04:00
|
|
|
virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
|
2015-03-21 19:28:04 +03:00
|
|
|
uint32_t aFilter) override;
|
2012-03-03 13:21:09 +04:00
|
|
|
|
|
|
|
private:
|
|
|
|
bool mHasValidDimensions;
|
2004-11-23 16:51:57 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Implementation
|
|
|
|
|
2005-11-11 05:36:29 +03:00
|
|
|
nsIFrame*
|
2009-01-19 21:31:34 +03:00
|
|
|
NS_NewSVGUseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
2004-11-23 16:51:57 +03:00
|
|
|
{
|
2006-03-27 01:30:36 +04:00
|
|
|
return new (aPresShell) nsSVGUseFrame(aContext);
|
2004-11-23 16:51:57 +03:00
|
|
|
}
|
|
|
|
|
2009-09-12 20:49:24 +04:00
|
|
|
NS_IMPL_FRAMEARENA_HELPERS(nsSVGUseFrame)
|
|
|
|
|
2004-11-23 16:51:57 +03:00
|
|
|
//----------------------------------------------------------------------
|
2009-01-12 22:20:59 +03:00
|
|
|
// nsQueryFrame methods
|
2004-11-23 16:51:57 +03:00
|
|
|
|
2009-01-12 22:20:59 +03:00
|
|
|
NS_QUERYFRAME_HEAD(nsSVGUseFrame)
|
|
|
|
NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
|
2016-04-18 10:46:09 +03:00
|
|
|
NS_QUERYFRAME_TAIL_INHERITING(nsSVGGFrame)
|
2004-11-23 16:51:57 +03:00
|
|
|
|
2006-03-02 23:22:19 +03:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsIFrame methods:
|
|
|
|
|
2013-03-20 05:47:48 +04:00
|
|
|
void
|
2014-05-25 02:20:40 +04:00
|
|
|
nsSVGUseFrame::Init(nsIContent* aContent,
|
|
|
|
nsContainerFrame* aParent,
|
|
|
|
nsIFrame* aPrevInFlow)
|
2009-01-19 21:31:34 +03:00
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
2014-02-18 11:47:48 +04:00
|
|
|
nsresult
|
2012-08-22 19:56:38 +04:00
|
|
|
nsSVGUseFrame::AttributeChanged(int32_t aNameSpaceID,
|
2006-03-02 23:22:19 +03:00
|
|
|
nsIAtom* aAttribute,
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t aModType)
|
2006-03-02 23:22:19 +03:00
|
|
|
{
|
2013-01-17 00:50:58 +04:00
|
|
|
SVGUseElement *useElement = static_cast<SVGUseElement*>(mContent);
|
2012-06-23 20:36:46 +04:00
|
|
|
|
2011-10-08 10:32:44 +04:00
|
|
|
if (aNameSpaceID == kNameSpaceID_None) {
|
2016-07-05 11:37:17 +03:00
|
|
|
if (aAttribute == nsGkAtoms::x || aAttribute == nsGkAtoms::y) {
|
2011-10-08 10:32:44 +04:00
|
|
|
// make sure our cached transform matrix gets (lazily) updated
|
2012-07-30 18:20:58 +04:00
|
|
|
mCanvasTM = nullptr;
|
2014-11-06 12:30:11 +03:00
|
|
|
nsLayoutUtils::PostRestyleEvent(
|
|
|
|
useElement, nsRestyleHint(0),
|
|
|
|
nsChangeHint_InvalidateRenderingObservers);
|
2012-11-28 13:42:13 +04:00
|
|
|
nsSVGUtils::ScheduleReflowSVG(this);
|
2011-10-08 10:32:44 +04:00
|
|
|
nsSVGUtils::NotifyChildrenOfSVGChange(this, TRANSFORM_CHANGED);
|
|
|
|
} else if (aAttribute == nsGkAtoms::width ||
|
|
|
|
aAttribute == nsGkAtoms::height) {
|
2012-06-23 20:36:46 +04:00
|
|
|
bool invalidate = false;
|
|
|
|
if (mHasValidDimensions != useElement->HasValidDimensions()) {
|
2012-03-03 13:21:09 +04:00
|
|
|
mHasValidDimensions = !mHasValidDimensions;
|
2012-06-23 20:36:46 +04:00
|
|
|
invalidate = true;
|
|
|
|
}
|
|
|
|
if (useElement->OurWidthAndHeightAreUsed()) {
|
|
|
|
invalidate = true;
|
|
|
|
useElement->SyncWidthOrHeight(aAttribute);
|
|
|
|
}
|
|
|
|
if (invalidate) {
|
2014-11-06 12:30:11 +03:00
|
|
|
nsLayoutUtils::PostRestyleEvent(
|
|
|
|
useElement, nsRestyleHint(0),
|
|
|
|
nsChangeHint_InvalidateRenderingObservers);
|
2012-11-28 13:42:13 +04:00
|
|
|
nsSVGUtils::ScheduleReflowSVG(this);
|
2012-03-03 13:21:09 +04:00
|
|
|
}
|
2011-10-08 10:32:44 +04:00
|
|
|
}
|
2016-07-05 11:37:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((aNameSpaceID == kNameSpaceID_XLink ||
|
|
|
|
aNameSpaceID == kNameSpaceID_None) &&
|
|
|
|
aAttribute == nsGkAtoms::href) {
|
2011-10-08 10:32:44 +04:00
|
|
|
// we're changing our nature, clear out the clone information
|
2014-11-06 12:30:11 +03:00
|
|
|
nsLayoutUtils::PostRestyleEvent(
|
|
|
|
useElement, nsRestyleHint(0),
|
|
|
|
nsChangeHint_InvalidateRenderingObservers);
|
2012-11-28 13:42:13 +04:00
|
|
|
nsSVGUtils::ScheduleReflowSVG(this);
|
2012-07-30 18:20:58 +04:00
|
|
|
useElement->mOriginal = nullptr;
|
2012-06-23 20:36:46 +04:00
|
|
|
useElement->UnlinkSource();
|
|
|
|
useElement->TriggerReclone();
|
2006-03-02 23:22:19 +03:00
|
|
|
}
|
|
|
|
|
2016-04-18 10:46:09 +03:00
|
|
|
return nsSVGGFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
|
2006-03-02 23:22:19 +03:00
|
|
|
}
|
|
|
|
|
2007-02-18 20:34:09 +03:00
|
|
|
void
|
2009-12-24 08:21:15 +03:00
|
|
|
nsSVGUseFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
2007-02-18 20:34:09 +03:00
|
|
|
{
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<SVGUseElement> use = static_cast<SVGUseElement*>(mContent);
|
2016-04-18 10:46:09 +03:00
|
|
|
nsSVGGFrame::DestroyFrom(aDestructRoot);
|
2007-06-18 19:30:57 +04:00
|
|
|
use->DestroyAnonymousContent();
|
2007-02-18 20:34:09 +03:00
|
|
|
}
|
|
|
|
|
2004-11-23 16:51:57 +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-05-17 08:05:09 +04:00
|
|
|
void
|
2012-07-22 04:01:44 +04:00
|
|
|
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;
|
2013-01-17 00:50:58 +04:00
|
|
|
static_cast<SVGUseElement*>(mContent)->
|
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),
|
|
|
|
PresContext()->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-02-01 20:25:44 +04:00
|
|
|
void
|
2012-08-22 19:56:38 +04:00
|
|
|
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'
|
2013-01-17 00:50:58 +04:00
|
|
|
SVGUseElement *use = static_cast<SVGUseElement*>(mContent);
|
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
|
|
|
}
|
|
|
|
|
2004-11-23 16:51:57 +03:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsIAnonymousContentCreator methods:
|
|
|
|
|
2007-02-18 20:34:09 +03:00
|
|
|
nsresult
|
2011-05-07 00:04:44 +04:00
|
|
|
nsSVGUseFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
|
2004-11-23 16:51:57 +03:00
|
|
|
{
|
2013-01-17 00:50:58 +04:00
|
|
|
SVGUseElement *use = static_cast<SVGUseElement*>(mContent);
|
2004-11-23 16:51:57 +03:00
|
|
|
|
2007-02-18 20:34:09 +03:00
|
|
|
nsIContent* clone = use->CreateAnonymousContent();
|
2014-11-06 12:30:11 +03:00
|
|
|
nsLayoutUtils::PostRestyleEvent(
|
|
|
|
use, nsRestyleHint(0), nsChangeHint_InvalidateRenderingObservers);
|
2007-02-18 20:34:09 +03:00
|
|
|
if (!clone)
|
2004-11-23 16:51:57 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
2007-02-18 20:34:09 +03:00
|
|
|
if (!aElements.AppendElement(clone))
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
return NS_OK;
|
2004-11-23 16:51:57 +03:00
|
|
|
}
|
2010-02-11 20:34:01 +03:00
|
|
|
|
|
|
|
void
|
2014-07-16 22:41:57 +04:00
|
|
|
nsSVGUseFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t aFilter)
|
2010-02-11 20:34:01 +03:00
|
|
|
{
|
2013-01-17 00:50:58 +04:00
|
|
|
SVGUseElement *use = static_cast<SVGUseElement*>(mContent);
|
2010-02-11 20:34:01 +03:00
|
|
|
nsIContent* clone = use->GetAnonymousContent();
|
2014-07-16 22:41:57 +04:00
|
|
|
if (clone) {
|
|
|
|
aElements.AppendElement(clone);
|
|
|
|
}
|
2010-02-11 20:34:01 +03:00
|
|
|
}
|