--- a/dom/svg/SVGSymbolElement.cpp
+++ b/dom/svg/SVGSymbolElement.cpp
@@ -38,18 +38,72 @@ SVGSymbolElement::~SVGSymbolElement()
}
//----------------------------------------------------------------------
// nsIDOMNode methods
NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGSymbolElement)
//----------------------------------------------------------------------
+
+already_AddRefed<SVGAnimatedRect>
+SVGSymbolElement::ViewBox()
+{
+ return mViewBox.ToSVGAnimatedRect(this);
+}
+
+already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
+SVGSymbolElement::PreserveAspectRatio()
+{
+ return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(this);
+}
+
+//----------------------------------------------------------------------
+// nsIContent methods
+
+NS_IMETHODIMP_(bool)
+SVGSymbolElement::IsAttributeMapped(const nsIAtom* name) const
+{
+ static const MappedAttributeEntry* const map[] = {
+ sColorMap,
+ sFEFloodMap,
+ sFillStrokeMap,
+ sFiltersMap,
+ sFontSpecificationMap,
+ sGradientStopMap,
+ sGraphicsMap,
+ sLightingEffectsMap,
+ sMarkersMap,
+ sTextContentElementsMap,
+ sViewportsMap
+ };
+
+ return FindAttributeDependence(name, map) ||
+ SVGSymbolElementBase::IsAttributeMapped(name);
+}
+
+//----------------------------------------------------------------------
// SVGTests methods
bool
SVGSymbolElement::IsInChromeDoc() const
{
return nsContentUtils::IsChromeDoc(OwnerDoc());
}
+
+//----------------------------------------------------------------------
+// nsSVGElement methods
+
+nsSVGViewBox *
+SVGSymbolElement::GetViewBox()
+{
+ return &mViewBox;
+}
+
+SVGAnimatedPreserveAspectRatio *
+SVGSymbolElement::GetPreserveAspectRatio()
+{
+ return &mPreserveAspectRatio;
+}
+
} // namespace dom
-} // namespace mozilla
+} // namespace mozilla
\ No newline at end of file
--- a/dom/svg/SVGSymbolElement.h
+++ b/dom/svg/SVGSymbolElement.h
@@ -2,42 +2,61 @@
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_SVGSymbolElement_h
#define mozilla_dom_SVGSymbolElement_h
-#include "SVGViewportElement.h"
+#include "mozilla/dom/SVGTests.h"
+#include "nsSVGElement.h"
+#include "nsSVGViewBox.h"
+#include "SVGAnimatedPreserveAspectRatio.h"
nsresult NS_NewSVGSymbolElement(nsIContent **aResult,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
namespace mozilla {
namespace dom {
-typedef SVGViewportElement SVGSymbolElementBase;
+typedef nsSVGElement SVGSymbolElementBase;
-class SVGSymbolElement final : public SVGSymbolElementBase
+class SVGSymbolElement final : public SVGSymbolElementBase,
+ public SVGTests
{
protected:
friend nsresult (::NS_NewSVGSymbolElement(nsIContent **aResult,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
explicit SVGSymbolElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
~SVGSymbolElement();
virtual JSObject* WrapNode(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
public:
// interfaces:
+
NS_DECL_ISUPPORTS_INHERITED
+ // nsIContent interface
+ NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* name) const override;
+
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
bool aPreallocateChildren) const override;
+ // WebIDL
+ already_AddRefed<SVGAnimatedRect> ViewBox();
+ already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
+
// SVGTests
bool IsInChromeDoc() const override;
+
+protected:
+ virtual nsSVGViewBox *GetViewBox() override;
+ virtual SVGAnimatedPreserveAspectRatio *GetPreserveAspectRatio() override;
+
+ nsSVGViewBox mViewBox;
+ SVGAnimatedPreserveAspectRatio mPreserveAspectRatio;
};
} // namespace dom
} // namespace mozilla
-#endif // mozilla_dom_SVGSymbolElement_h
+#endif // mozilla_dom_SVGSymbolElement_h
\ No newline at end of file
--- a/dom/svg/SVGViewportElement.h
+++ b/dom/svg/SVGViewportElement.h
@@ -16,17 +16,17 @@
#include "SVGGraphicsElement.h"
#include "SVGImageContext.h"
#include "nsSVGViewBox.h"
#include "SVGPreserveAspectRatio.h"
#include "SVGAnimatedPreserveAspectRatio.h"
#include "mozilla/Attributes.h"
class nsSVGOuterSVGFrame;
-class nsSVGInnerSVGFrame;
+class nsSVGViewportFrame;
namespace mozilla {
class AutoPreserveAspectRatioOverride;
class DOMSVGAnimatedPreserveAspectRatio;
namespace dom {
class SVGAnimatedRect;
class SVGTransform;
@@ -44,17 +44,17 @@ public:
}
float width;
float height;
};
class SVGViewportElement : public SVGGraphicsElement
{
friend class ::nsSVGOuterSVGFrame;
- friend class ::nsSVGInnerSVGFrame;
+ friend class ::nsSVGViewportFrame;
protected:
SVGViewportElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
~SVGViewportElement();
public:
--- a/layout/svg/moz.build
+++ b/layout/svg/moz.build
@@ -50,16 +50,17 @@ UNIFIED_SOURCES += [
'nsSVGMarkerFrame.cpp',
'nsSVGMaskFrame.cpp',
'nsSVGOuterSVGFrame.cpp',
'nsSVGPatternFrame.cpp',
'nsSVGStopFrame.cpp',
'nsSVGSwitchFrame.cpp',
'nsSVGUseFrame.cpp',
'nsSVGUtils.cpp',
+ 'nsSVGViewportFrame.cpp',
'SVGContextPaint.cpp',
'SVGFEContainerFrame.cpp',
'SVGFEImageFrame.cpp',
'SVGFELeafFrame.cpp',
'SVGFEUnstyledLeafFrame.cpp',
'SVGGeometryFrame.cpp',
'SVGImageContext.cpp',
'SVGTextFrame.cpp',
--- a/layout/svg/nsSVGInnerSVGFrame.cpp
+++ b/layout/svg/nsSVGInnerSVGFrame.cpp
@@ -1,338 +1,36 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
// Main header first:
#include "nsSVGInnerSVGFrame.h"
-// Keep others in (case-insensitive) order:
-#include "gfx2DGlue.h"
-#include "gfxContext.h"
-#include "nsIFrame.h"
-#include "nsSVGDisplayableFrame.h"
-#include "nsSVGContainerFrame.h"
-#include "nsSVGIntegrationUtils.h"
-#include "mozilla/dom/SVGViewportElement.h"
-
-using namespace mozilla;
-using namespace mozilla::dom;
-using namespace mozilla::gfx;
-using namespace mozilla::image;
-
nsIFrame*
NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
{
return new (aPresShell) nsSVGInnerSVGFrame(aContext);
}
NS_IMPL_FRAMEARENA_HELPERS(nsSVGInnerSVGFrame)
//----------------------------------------------------------------------
// nsIFrame methods
NS_QUERYFRAME_HEAD(nsSVGInnerSVGFrame)
NS_QUERYFRAME_ENTRY(nsSVGInnerSVGFrame)
NS_QUERYFRAME_ENTRY(nsISVGSVGFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsSVGDisplayContainerFrame)
+NS_QUERYFRAME_TAIL_INHERITING(nsSVGViewportFrame)
#ifdef DEBUG
void
nsSVGInnerSVGFrame::Init(nsIContent* aContent,
nsContainerFrame* aParent,
nsIFrame* aPrevInFlow)
{
NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::svg),
"Content is not an SVG 'svg' element!");
- nsSVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
+ nsSVGViewportFrame::Init(aContent, aParent, aPrevInFlow);
}
#endif /* DEBUG */
-
-//----------------------------------------------------------------------
-// nsSVGDisplayableFrame methods
-
-void
-nsSVGInnerSVGFrame::PaintSVG(gfxContext& aContext,
- const gfxMatrix& aTransform,
- imgDrawingParams& aImgParams,
- const nsIntRect *aDirtyRect)
-{
- NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
- (mState & NS_FRAME_IS_NONDISPLAY),
- "If display lists are enabled, only painting of non-display "
- "SVG should take this code path");
-
- gfxContextAutoSaveRestore autoSR;
-
- if (StyleDisplay()->IsScrollableOverflow()) {
- float x, y, width, height;
- static_cast<SVGViewportElement*>(mContent)->
- GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
-
- if (width <= 0 || height <= 0) {
- return;
- }
-
- autoSR.SetContext(&aContext);
- gfxRect clipRect =
- nsSVGUtils::GetClipRectForFrame(this, x, y, width, height);
- nsSVGUtils::SetClipRect(&aContext, aTransform, clipRect);
- }
-
- nsSVGDisplayContainerFrame::PaintSVG(aContext, aTransform, aImgParams,
- aDirtyRect);
-}
-
-void
-nsSVGInnerSVGFrame::ReflowSVG()
-{
- // mRect must be set before FinishAndStoreOverflow is called in order
- // for our overflow areas to be clipped correctly.
- float x, y, width, height;
- static_cast<SVGViewportElement*>(mContent)->
- GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
- mRect = nsLayoutUtils::RoundGfxRectToAppRect(
- gfxRect(x, y, width, height),
- PresContext()->AppUnitsPerCSSPixel());
-
- // If we have a filter, we need to invalidate ourselves because filter
- // output can change even if none of our descendants need repainting.
- if (StyleEffects()->HasFilters()) {
- InvalidateFrame();
- }
-
- nsSVGDisplayContainerFrame::ReflowSVG();
-}
-
-void
-nsSVGInnerSVGFrame::NotifySVGChanged(uint32_t aFlags)
-{
- MOZ_ASSERT(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
- "Invalidation logic may need adjusting");
-
- if (aFlags & COORD_CONTEXT_CHANGED) {
-
- SVGViewportElement *svg = static_cast<SVGViewportElement*>(mContent);
-
- bool xOrYIsPercentage =
- svg->mLengthAttributes[SVGViewportElement::ATTR_X].IsPercentage() ||
- svg->mLengthAttributes[SVGViewportElement::ATTR_Y].IsPercentage();
- bool widthOrHeightIsPercentage =
- svg->mLengthAttributes[SVGViewportElement::ATTR_WIDTH].IsPercentage() ||
- svg->mLengthAttributes[SVGViewportElement::ATTR_HEIGHT].IsPercentage();
-
- if (xOrYIsPercentage || widthOrHeightIsPercentage) {
- // 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.
- nsSVGUtils::ScheduleReflowSVG(this);
- }
-
- // Coordinate context changes affect mCanvasTM if we have a
- // percentage 'x' or 'y', or if we have a percentage 'width' or 'height' AND
- // a 'viewBox'.
-
- if (!(aFlags & TRANSFORM_CHANGED) &&
- (xOrYIsPercentage ||
- (widthOrHeightIsPercentage && svg->HasViewBoxRect()))) {
- aFlags |= TRANSFORM_CHANGED;
- }
-
- if (svg->HasViewBoxRect() || !widthOrHeightIsPercentage) {
- // Remove COORD_CONTEXT_CHANGED, since we establish the coordinate
- // context for our descendants and this notification won't change its
- // dimensions:
- aFlags &= ~COORD_CONTEXT_CHANGED;
-
- if (!aFlags) {
- return; // No notification flags left
- }
- }
- }
-
- if (aFlags & TRANSFORM_CHANGED) {
- // make sure our cached transform matrix gets (lazily) updated
- mCanvasTM = nullptr;
- }
-
- nsSVGDisplayContainerFrame::NotifySVGChanged(aFlags);
-}
-
-SVGBBox
-nsSVGInnerSVGFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace,
- uint32_t aFlags)
-{
- // XXXjwatt It seems like authors would want the result to be clipped by the
- // viewport we establish if IsScrollableOverflow() is true. We should
- // consider doing that. See bug 1350755.
-
- SVGBBox bbox;
-
- if (aFlags & nsSVGUtils::eForGetClientRects) {
- // XXXjwatt For consistency with the old code this code includes the
- // viewport we establish in the result, but only includes the bounds of our
- // descendants if they are not clipped to that viewport. However, this is
- // both inconsistent with Chrome and with the specs. See bug 1350755.
- // Ideally getClientRects/getBoundingClientRect should be consistent with
- // getBBox.
- float x, y, w, h;
- static_cast<SVGViewportElement*>(mContent)->
- GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
- if (w < 0.0f) w = 0.0f;
- if (h < 0.0f) h = 0.0f;
- Rect viewport(x, y, w, h);
- bbox = aToBBoxUserspace.TransformBounds(viewport);
- if (StyleDisplay()->IsScrollableOverflow()) {
- return bbox;
- }
- // Else we're not clipping to our viewport so we fall through and include
- // the bounds of our children.
- }
-
- SVGBBox descendantsBbox =
- nsSVGDisplayContainerFrame::GetBBoxContribution(aToBBoxUserspace, aFlags);
-
- bbox.UnionEdges(descendantsBbox);
-
- return bbox;
-}
-
-nsresult
-nsSVGInnerSVGFrame::AttributeChanged(int32_t aNameSpaceID,
- nsIAtom* aAttribute,
- int32_t aModType)
-{
- if (aNameSpaceID == kNameSpaceID_None &&
- !(GetStateBits() & NS_FRAME_IS_NONDISPLAY)) {
-
- SVGViewportElement* content = static_cast<SVGViewportElement*>(mContent);
-
- if (aAttribute == nsGkAtoms::width ||
- aAttribute == nsGkAtoms::height) {
- nsLayoutUtils::PostRestyleEvent(
- mContent->AsElement(), nsRestyleHint(0),
- nsChangeHint_InvalidateRenderingObservers);
- nsSVGUtils::ScheduleReflowSVG(this);
-
- if (content->HasViewBoxOrSyntheticViewBox()) {
- // make sure our cached transform matrix gets (lazily) updated
- mCanvasTM = nullptr;
- content->ChildrenOnlyTransformChanged();
- nsSVGUtils::NotifyChildrenOfSVGChange(this, TRANSFORM_CHANGED);
- } else {
- uint32_t flags = COORD_CONTEXT_CHANGED;
- if (mCanvasTM && mCanvasTM->IsSingular()) {
- mCanvasTM = nullptr;
- flags |= TRANSFORM_CHANGED;
- }
- nsSVGUtils::NotifyChildrenOfSVGChange(this, flags);
- }
-
- } else if (aAttribute == nsGkAtoms::transform ||
- aAttribute == nsGkAtoms::preserveAspectRatio ||
- aAttribute == nsGkAtoms::viewBox ||
- aAttribute == nsGkAtoms::x ||
- aAttribute == nsGkAtoms::y) {
- // make sure our cached transform matrix gets (lazily) updated
- mCanvasTM = nullptr;
-
- nsSVGUtils::NotifyChildrenOfSVGChange(
- this, aAttribute == nsGkAtoms::viewBox ?
- TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED : TRANSFORM_CHANGED);
-
- // We don't invalidate for transform changes (the layers code does that).
- // Also note that SVGTransformableElement::GetAttributeChangeHint will
- // return nsChangeHint_UpdateOverflow for "transform" attribute changes
- // and cause DoApplyRenderingChangeToTree to make the SchedulePaint call.
-
- if (aAttribute == nsGkAtoms::x || aAttribute == nsGkAtoms::y) {
- nsLayoutUtils::PostRestyleEvent(
- mContent->AsElement(), nsRestyleHint(0),
- nsChangeHint_InvalidateRenderingObservers);
- nsSVGUtils::ScheduleReflowSVG(this);
- } else if (aAttribute == nsGkAtoms::viewBox ||
- (aAttribute == nsGkAtoms::preserveAspectRatio &&
- content->HasViewBoxOrSyntheticViewBox())) {
- content->ChildrenOnlyTransformChanged();
- // SchedulePaint sets a global state flag so we only need to call it once
- // (on ourself is fine), not once on each child (despite bug 828240).
- SchedulePaint();
- }
- }
- }
-
- return NS_OK;
-}
-
-nsIFrame*
-nsSVGInnerSVGFrame::GetFrameForPoint(const gfxPoint& aPoint)
-{
- NS_ASSERTION(!NS_SVGDisplayListHitTestingEnabled() ||
- (mState & NS_FRAME_IS_NONDISPLAY),
- "If display lists are enabled, only hit-testing of non-display "
- "SVG should take this code path");
-
- if (StyleDisplay()->IsScrollableOverflow()) {
- Rect clip;
- static_cast<nsSVGElement*>(mContent)->
- GetAnimatedLengthValues(&clip.x, &clip.y,
- &clip.width, &clip.height, nullptr);
- if (!clip.Contains(ToPoint(aPoint))) {
- return nullptr;
- }
- }
-
- return nsSVGDisplayContainerFrame::GetFrameForPoint(aPoint);
-}
-
-//----------------------------------------------------------------------
-// nsISVGSVGFrame methods:
-
-void
-nsSVGInnerSVGFrame::NotifyViewportOrTransformChanged(uint32_t aFlags)
-{
- // The dimensions of inner-<svg> frames are purely defined by their "width"
- // and "height" attributes, and transform changes can only occur as a result
- // of changes to their "width", "height", "viewBox" or "preserveAspectRatio"
- // attributes. Changes to all of these attributes are handled in
- // AttributeChanged(), so we should never be called.
- NS_ERROR("Not called for nsSVGInnerSVGFrame");
-}
-
-//----------------------------------------------------------------------
-// nsSVGContainerFrame methods:
-
-gfxMatrix
-nsSVGInnerSVGFrame::GetCanvasTM()
-{
- if (!mCanvasTM) {
- NS_ASSERTION(GetParent(), "null parent");
-
- nsSVGContainerFrame *parent = static_cast<nsSVGContainerFrame*>(GetParent());
- SVGViewportElement *content = static_cast<SVGViewportElement*>(mContent);
-
- gfxMatrix tm = content->PrependLocalTransformsTo(parent->GetCanvasTM());
-
- mCanvasTM = new gfxMatrix(tm);
- }
- return *mCanvasTM;
-}
-
-bool
-nsSVGInnerSVGFrame::HasChildrenOnlyTransform(gfx::Matrix *aTransform) const
-{
- SVGSVGElement *content = static_cast<SVGSVGElement*>(mContent);
-
- if (content->HasViewBoxOrSyntheticViewBox()) {
- // XXX Maybe return false if the transform is the identity transform?
- if (aTransform) {
- *aTransform = content->GetViewBoxTransform();
- }
- return true;
- }
- return false;
-}
--- a/layout/svg/nsSVGInnerSVGFrame.h
+++ b/layout/svg/nsSVGInnerSVGFrame.h
@@ -1,32 +1,26 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef __NS_SVGINNERSVGFRAME_H__
#define __NS_SVGINNERSVGFRAME_H__
-#include "mozilla/Attributes.h"
-#include "nsAutoPtr.h"
-#include "nsSVGContainerFrame.h"
-#include "nsISVGSVGFrame.h"
-
-class gfxContext;
+#include "nsSVGViewportFrame.h"
class nsSVGInnerSVGFrame final
- : public nsSVGDisplayContainerFrame
- , public nsISVGSVGFrame
+ : public nsSVGViewportFrame
{
friend nsIFrame*
NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
protected:
explicit nsSVGInnerSVGFrame(nsStyleContext* aContext)
- : nsSVGDisplayContainerFrame(aContext, kClassID)
+ : nsSVGViewportFrame(aContext, kClassID)
{
}
public:
NS_DECL_QUERYFRAME
NS_DECL_FRAMEARENA_HELPERS(nsSVGInnerSVGFrame)
#ifdef DEBUG
@@ -36,39 +30,12 @@ public:
#endif
#ifdef DEBUG_FRAME_DUMP
virtual nsresult GetFrameName(nsAString& aResult) const override
{
return MakeFrameName(NS_LITERAL_STRING("SVGInnerSVG"), aResult);
}
#endif
-
- virtual nsresult AttributeChanged(int32_t aNameSpaceID,
- nsIAtom* aAttribute,
- int32_t aModType) override;
-
- // nsSVGDisplayableFrame interface:
- virtual void PaintSVG(gfxContext& aContext,
- const gfxMatrix& aTransform,
- imgDrawingParams& aImgParams,
- const nsIntRect* aDirtyRect = nullptr) override;
- virtual void ReflowSVG() override;
- virtual void NotifySVGChanged(uint32_t aFlags) override;
- SVGBBox GetBBoxContribution(const Matrix &aToBBoxUserspace,
- uint32_t aFlags) override;
- virtual nsIFrame* GetFrameForPoint(const gfxPoint& aPoint) override;
-
- // nsSVGContainerFrame methods:
- virtual gfxMatrix GetCanvasTM() override;
-
- virtual bool HasChildrenOnlyTransform(Matrix *aTransform) const override;
-
- // nsISVGSVGFrame interface:
- virtual void NotifyViewportOrTransformChanged(uint32_t aFlags) override;
-
-protected:
-
- nsAutoPtr<gfxMatrix> mCanvasTM;
};
#endif
new file mode 100644
--- /dev/null
+++ b/layout/svg/nsSVGViewportFrame.cpp
@@ -0,0 +1,309 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+// Main header first:
+#include "nsSVGViewportFrame.h"
+
+// Keep others in (case-insensitive) order:
+#include "gfx2DGlue.h"
+#include "gfxContext.h"
+#include "nsIFrame.h"
+#include "nsSVGDisplayableFrame.h"
+#include "nsSVGContainerFrame.h"
+#include "nsSVGIntegrationUtils.h"
+#include "mozilla/dom/SVGViewportElement.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+using namespace mozilla::gfx;
+using namespace mozilla::image;
+
+//----------------------------------------------------------------------
+// nsSVGDisplayableFrame methods
+
+void
+nsSVGViewportFrame::PaintSVG(gfxContext& aContext,
+ const gfxMatrix& aTransform,
+ imgDrawingParams& aImgParams,
+ const nsIntRect *aDirtyRect)
+{
+ NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
+ (mState & NS_FRAME_IS_NONDISPLAY),
+ "If display lists are enabled, only painting of non-display "
+ "SVG should take this code path");
+
+ gfxContextAutoSaveRestore autoSR;
+
+ if (StyleDisplay()->IsScrollableOverflow()) {
+ float x, y, width, height;
+ static_cast<SVGViewportElement*>(mContent)->
+ GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
+
+ if (width <= 0 || height <= 0) {
+ return;
+ }
+
+ autoSR.SetContext(&aContext);
+ gfxRect clipRect =
+ nsSVGUtils::GetClipRectForFrame(this, x, y, width, height);
+ nsSVGUtils::SetClipRect(&aContext, aTransform, clipRect);
+ }
+
+ nsSVGDisplayContainerFrame::PaintSVG(aContext, aTransform, aImgParams,
+ aDirtyRect);
+}
+
+void
+nsSVGViewportFrame::ReflowSVG()
+{
+ // mRect must be set before FinishAndStoreOverflow is called in order
+ // for our overflow areas to be clipped correctly.
+ float x, y, width, height;
+ static_cast<SVGViewportElement*>(mContent)->
+ GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
+ mRect = nsLayoutUtils::RoundGfxRectToAppRect(
+ gfxRect(x, y, width, height),
+ PresContext()->AppUnitsPerCSSPixel());
+
+ // If we have a filter, we need to invalidate ourselves because filter
+ // output can change even if none of our descendants need repainting.
+ if (StyleEffects()->HasFilters()) {
+ InvalidateFrame();
+ }
+
+ nsSVGDisplayContainerFrame::ReflowSVG();
+}
+
+void
+nsSVGViewportFrame::NotifySVGChanged(uint32_t aFlags)
+{
+ MOZ_ASSERT(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
+ "Invalidation logic may need adjusting");
+
+ if (aFlags & COORD_CONTEXT_CHANGED) {
+
+ SVGViewportElement *svg = static_cast<SVGViewportElement*>(mContent);
+
+ bool xOrYIsPercentage =
+ svg->mLengthAttributes[SVGViewportElement::ATTR_X].IsPercentage() ||
+ svg->mLengthAttributes[SVGViewportElement::ATTR_Y].IsPercentage();
+ bool widthOrHeightIsPercentage =
+ svg->mLengthAttributes[SVGViewportElement::ATTR_WIDTH].IsPercentage() ||
+ svg->mLengthAttributes[SVGViewportElement::ATTR_HEIGHT].IsPercentage();
+
+ if (xOrYIsPercentage || widthOrHeightIsPercentage) {
+ // 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.
+ nsSVGUtils::ScheduleReflowSVG(this);
+ }
+
+ // Coordinate context changes affect mCanvasTM if we have a
+ // percentage 'x' or 'y', or if we have a percentage 'width' or 'height' AND
+ // a 'viewBox'.
+
+ if (!(aFlags & TRANSFORM_CHANGED) &&
+ (xOrYIsPercentage ||
+ (widthOrHeightIsPercentage && svg->HasViewBoxRect()))) {
+ aFlags |= TRANSFORM_CHANGED;
+ }
+
+ if (svg->HasViewBoxRect() || !widthOrHeightIsPercentage) {
+ // Remove COORD_CONTEXT_CHANGED, since we establish the coordinate
+ // context for our descendants and this notification won't change its
+ // dimensions:
+ aFlags &= ~COORD_CONTEXT_CHANGED;
+
+ if (!aFlags) {
+ return; // No notification flags left
+ }
+ }
+ }
+
+ if (aFlags & TRANSFORM_CHANGED) {
+ // make sure our cached transform matrix gets (lazily) updated
+ mCanvasTM = nullptr;
+ }
+
+ nsSVGDisplayContainerFrame::NotifySVGChanged(aFlags);
+}
+
+SVGBBox
+nsSVGViewportFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace,
+ uint32_t aFlags)
+{
+ // XXXjwatt It seems like authors would want the result to be clipped by the
+ // viewport we establish if IsScrollableOverflow() is true. We should
+ // consider doing that. See bug 1350755.
+
+ SVGBBox bbox;
+
+ if (aFlags & nsSVGUtils::eForGetClientRects) {
+ // XXXjwatt For consistency with the old code this code includes the
+ // viewport we establish in the result, but only includes the bounds of our
+ // descendants if they are not clipped to that viewport. However, this is
+ // both inconsistent with Chrome and with the specs. See bug 1350755.
+ // Ideally getClientRects/getBoundingClientRect should be consistent with
+ // getBBox.
+ float x, y, w, h;
+ static_cast<SVGViewportElement*>(mContent)->
+ GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
+ if (w < 0.0f) w = 0.0f;
+ if (h < 0.0f) h = 0.0f;
+ Rect viewport(x, y, w, h);
+ bbox = aToBBoxUserspace.TransformBounds(viewport);
+ if (StyleDisplay()->IsScrollableOverflow()) {
+ return bbox;
+ }
+ // Else we're not clipping to our viewport so we fall through and include
+ // the bounds of our children.
+ }
+
+ SVGBBox descendantsBbox =
+ nsSVGDisplayContainerFrame::GetBBoxContribution(aToBBoxUserspace, aFlags);
+
+ bbox.UnionEdges(descendantsBbox);
+
+ return bbox;
+}
+
+nsresult
+nsSVGViewportFrame::AttributeChanged(int32_t aNameSpaceID,
+ nsIAtom* aAttribute,
+ int32_t aModType)
+{
+ if (aNameSpaceID == kNameSpaceID_None &&
+ !(GetStateBits() & NS_FRAME_IS_NONDISPLAY)) {
+
+ SVGViewportElement* content = static_cast<SVGViewportElement*>(mContent);
+
+ if (aAttribute == nsGkAtoms::width ||
+ aAttribute == nsGkAtoms::height) {
+ nsLayoutUtils::PostRestyleEvent(
+ mContent->AsElement(), nsRestyleHint(0),
+ nsChangeHint_InvalidateRenderingObservers);
+ nsSVGUtils::ScheduleReflowSVG(this);
+
+ if (content->HasViewBoxOrSyntheticViewBox()) {
+ // make sure our cached transform matrix gets (lazily) updated
+ mCanvasTM = nullptr;
+ content->ChildrenOnlyTransformChanged();
+ nsSVGUtils::NotifyChildrenOfSVGChange(this, TRANSFORM_CHANGED);
+ } else {
+ uint32_t flags = COORD_CONTEXT_CHANGED;
+ if (mCanvasTM && mCanvasTM->IsSingular()) {
+ mCanvasTM = nullptr;
+ flags |= TRANSFORM_CHANGED;
+ }
+ nsSVGUtils::NotifyChildrenOfSVGChange(this, flags);
+ }
+
+ } else if (aAttribute == nsGkAtoms::transform ||
+ aAttribute == nsGkAtoms::preserveAspectRatio ||
+ aAttribute == nsGkAtoms::viewBox ||
+ aAttribute == nsGkAtoms::x ||
+ aAttribute == nsGkAtoms::y) {
+ // make sure our cached transform matrix gets (lazily) updated
+ mCanvasTM = nullptr;
+
+ nsSVGUtils::NotifyChildrenOfSVGChange(
+ this, aAttribute == nsGkAtoms::viewBox ?
+ TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED : TRANSFORM_CHANGED);
+
+ // We don't invalidate for transform changes (the layers code does that).
+ // Also note that SVGTransformableElement::GetAttributeChangeHint will
+ // return nsChangeHint_UpdateOverflow for "transform" attribute changes
+ // and cause DoApplyRenderingChangeToTree to make the SchedulePaint call.
+
+ if (aAttribute == nsGkAtoms::x || aAttribute == nsGkAtoms::y) {
+ nsLayoutUtils::PostRestyleEvent(
+ mContent->AsElement(), nsRestyleHint(0),
+ nsChangeHint_InvalidateRenderingObservers);
+ nsSVGUtils::ScheduleReflowSVG(this);
+ } else if (aAttribute == nsGkAtoms::viewBox ||
+ (aAttribute == nsGkAtoms::preserveAspectRatio &&
+ content->HasViewBoxOrSyntheticViewBox())) {
+ content->ChildrenOnlyTransformChanged();
+ // SchedulePaint sets a global state flag so we only need to call it once
+ // (on ourself is fine), not once on each child (despite bug 828240).
+ SchedulePaint();
+ }
+ }
+ }
+
+ return NS_OK;
+}
+
+nsIFrame*
+nsSVGViewportFrame::GetFrameForPoint(const gfxPoint& aPoint)
+{
+ NS_ASSERTION(!NS_SVGDisplayListHitTestingEnabled() ||
+ (mState & NS_FRAME_IS_NONDISPLAY),
+ "If display lists are enabled, only hit-testing of non-display "
+ "SVG should take this code path");
+
+ if (StyleDisplay()->IsScrollableOverflow()) {
+ Rect clip;
+ static_cast<nsSVGElement*>(mContent)->
+ GetAnimatedLengthValues(&clip.x, &clip.y,
+ &clip.width, &clip.height, nullptr);
+ if (!clip.Contains(ToPoint(aPoint))) {
+ return nullptr;
+ }
+ }
+
+ return nsSVGDisplayContainerFrame::GetFrameForPoint(aPoint);
+}
+
+//----------------------------------------------------------------------
+// nsISVGSVGFrame methods:
+
+void
+nsSVGViewportFrame::NotifyViewportOrTransformChanged(uint32_t aFlags)
+{
+ // The dimensions of inner-<svg> frames are purely defined by their "width"
+ // and "height" attributes, and transform changes can only occur as a result
+ // of changes to their "width", "height", "viewBox" or "preserveAspectRatio"
+ // attributes. Changes to all of these attributes are handled in
+ // AttributeChanged(), so we should never be called.
+ NS_ERROR("Not called for nsSVGViewportFrame");
+}
+
+//----------------------------------------------------------------------
+// nsSVGContainerFrame methods:
+
+gfxMatrix
+nsSVGViewportFrame::GetCanvasTM()
+{
+ if (!mCanvasTM) {
+ NS_ASSERTION(GetParent(), "null parent");
+
+ nsSVGContainerFrame *parent = static_cast<nsSVGContainerFrame*>(GetParent());
+ SVGViewportElement *content = static_cast<SVGViewportElement*>(mContent);
+
+ gfxMatrix tm = content->PrependLocalTransformsTo(parent->GetCanvasTM());
+
+ mCanvasTM = new gfxMatrix(tm);
+ }
+ return *mCanvasTM;
+}
+
+bool
+nsSVGViewportFrame::HasChildrenOnlyTransform(gfx::Matrix *aTransform) const
+{
+ SVGViewportElement *content = static_cast<SVGViewportElement*>(mContent);
+
+ if (content->HasViewBoxOrSyntheticViewBox()) {
+ // XXX Maybe return false if the transform is the identity transform?
+ if (aTransform) {
+ *aTransform = content->GetViewBoxTransform();
+ }
+ return true;
+ }
+ return false;
+}
new file mode 100644
--- /dev/null
+++ b/layout/svg/nsSVGViewportFrame.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#ifndef __NS_SVGVIEWPORTFRAME_H__
+#define __NS_SVGVIEWPORTFRAME_H__
+
+#include "mozilla/Attributes.h"
+#include "nsAutoPtr.h"
+#include "nsSVGContainerFrame.h"
+#include "nsISVGSVGFrame.h"
+
+class gfxContext;
+/**
+ * Superclass for inner SVG frames and symbol frames.
+ */
+class nsSVGViewportFrame
+ : public nsSVGDisplayContainerFrame
+ , public nsISVGSVGFrame
+{
+protected:
+ nsSVGViewportFrame(nsStyleContext* aContext, nsIFrame::ClassID aID)
+ : nsSVGDisplayContainerFrame(aContext, aID)
+ {
+ }
+public:
+
+ virtual nsresult AttributeChanged(int32_t aNameSpaceID,
+ nsIAtom* aAttribute,
+ int32_t aModType) override;
+
+ // nsSVGDisplayableFrame interface:
+ virtual void PaintSVG(gfxContext& aContext,
+ const gfxMatrix& aTransform,
+ imgDrawingParams& aImgParams,
+ const nsIntRect* aDirtyRect = nullptr) override;
+ virtual void ReflowSVG() override;
+ virtual void NotifySVGChanged(uint32_t aFlags) override;
+ SVGBBox GetBBoxContribution(const Matrix &aToBBoxUserspace,
+ uint32_t aFlags) override;
+ virtual nsIFrame* GetFrameForPoint(const gfxPoint& aPoint) override;
+
+ // nsSVGContainerFrame methods:
+ virtual gfxMatrix GetCanvasTM() override;
+
+ virtual bool HasChildrenOnlyTransform(Matrix *aTransform) const override;
+
+ // nsISVGSVGFrame interface:
+ virtual void NotifyViewportOrTransformChanged(uint32_t aFlags) override;
+
+protected:
+
+ nsAutoPtr<gfxMatrix> mCanvasTM;
+};
+
+#endif // __NS_SVGVIEWPORTFRAME_H__
+