123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- /* -*- 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/. */
- // Keep in (case-insensitive) order:
- #include "gfxRect.h"
- #include "nsSVGEffects.h"
- #include "nsSVGGFrame.h"
- #include "mozilla/dom/SVGSwitchElement.h"
- #include "nsSVGUtils.h"
- using namespace mozilla::gfx;
- using namespace mozilla::image;
- class nsSVGSwitchFrame : public nsSVGGFrame
- {
- friend nsIFrame*
- NS_NewSVGSwitchFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
- protected:
- explicit nsSVGSwitchFrame(nsStyleContext* aContext)
- : nsSVGGFrame(aContext) {}
- public:
- NS_DECL_FRAMEARENA_HELPERS
- #ifdef DEBUG
- virtual void Init(nsIContent* aContent,
- nsContainerFrame* aParent,
- nsIFrame* aPrevInFlow) override;
- #endif
- /**
- * Get the "type" of the frame
- *
- * @see nsGkAtoms::svgSwitchFrame
- */
- virtual nsIAtom* GetType() const override;
- #ifdef DEBUG_FRAME_DUMP
- virtual nsresult GetFrameName(nsAString& aResult) const override
- {
- return MakeFrameName(NS_LITERAL_STRING("SVGSwitch"), aResult);
- }
- #endif
- virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
- const nsDisplayListSet& aLists) override;
- // nsISVGChildFrame interface:
- virtual DrawResult PaintSVG(gfxContext& aContext,
- const gfxMatrix& aTransform,
- const nsIntRect* aDirtyRect = nullptr) override;
- nsIFrame* GetFrameForPoint(const gfxPoint& aPoint) override;
- nsRect GetCoveredRegion() override;
- virtual void ReflowSVG() override;
- virtual SVGBBox GetBBoxContribution(const Matrix &aToBBoxUserspace,
- uint32_t aFlags) override;
- private:
- nsIFrame *GetActiveChildFrame();
- };
- //----------------------------------------------------------------------
- // Implementation
- nsIFrame*
- NS_NewSVGSwitchFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
- {
- return new (aPresShell) nsSVGSwitchFrame(aContext);
- }
- NS_IMPL_FRAMEARENA_HELPERS(nsSVGSwitchFrame)
- #ifdef DEBUG
- void
- nsSVGSwitchFrame::Init(nsIContent* aContent,
- nsContainerFrame* aParent,
- nsIFrame* aPrevInFlow)
- {
- NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::svgSwitch),
- "Content is not an SVG switch");
- nsSVGGFrame::Init(aContent, aParent, aPrevInFlow);
- }
- #endif /* DEBUG */
- nsIAtom *
- nsSVGSwitchFrame::GetType() const
- {
- return nsGkAtoms::svgSwitchFrame;
- }
- void
- nsSVGSwitchFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
- const nsDisplayListSet& aLists)
- {
- nsIFrame* kid = GetActiveChildFrame();
- if (kid) {
- BuildDisplayListForChild(aBuilder, kid, aLists);
- }
- }
- DrawResult
- nsSVGSwitchFrame::PaintSVG(gfxContext& aContext,
- const gfxMatrix& aTransform,
- 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");
- if (StyleEffects()->mOpacity == 0.0)
- return DrawResult::SUCCESS;
- DrawResult result = DrawResult::SUCCESS;
- nsIFrame *kid = GetActiveChildFrame();
- if (kid) {
- gfxMatrix tm = aTransform;
- if (kid->GetContent()->IsSVGElement()) {
- tm = static_cast<nsSVGElement*>(kid->GetContent())->
- PrependLocalTransformsTo(tm, eUserSpaceToParent);
- }
- result = nsSVGUtils::PaintFrameWithEffects(kid, aContext, tm, aDirtyRect);
- }
- return result;
- }
- nsIFrame*
- nsSVGSwitchFrame::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");
- nsIFrame *kid = GetActiveChildFrame();
- nsISVGChildFrame* svgFrame = do_QueryFrame(kid);
- if (svgFrame) {
- // Transform the point from our SVG user space to our child's.
- gfxPoint point = aPoint;
- gfxMatrix m =
- static_cast<const nsSVGElement*>(mContent)->
- PrependLocalTransformsTo(gfxMatrix(), eChildToUserSpace);
- m = static_cast<const nsSVGElement*>(kid->GetContent())->
- PrependLocalTransformsTo(m, eUserSpaceToParent);
- if (!m.IsIdentity()) {
- if (!m.Invert()) {
- return nullptr;
- }
- point = m.Transform(point);
- }
- return svgFrame->GetFrameForPoint(point);
- }
- return nullptr;
- }
- nsRect
- nsSVGSwitchFrame::GetCoveredRegion()
- {
- nsRect rect;
- nsIFrame *kid = GetActiveChildFrame();
- nsISVGChildFrame* child = do_QueryFrame(kid);
- if (child) {
- rect = child->GetCoveredRegion();
- }
- return rect;
- }
- void
- nsSVGSwitchFrame::ReflowSVG()
- {
- NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingReflowSVG(this),
- "This call is probably a wasteful mistake");
- MOZ_ASSERT(!(GetStateBits() & NS_FRAME_IS_NONDISPLAY),
- "ReflowSVG mechanism not designed for this");
- if (!nsSVGUtils::NeedsReflowSVG(this)) {
- return;
- }
- // If the NS_FRAME_FIRST_REFLOW bit has been removed from our parent frame,
- // then our outer-<svg> has previously had its initial reflow. In that case
- // we need to make sure that that bit has been removed from ourself _before_
- // recursing over our children to ensure that they know too. Otherwise, we
- // need to remove it _after_ recursing over our children so that they know
- // the initial reflow is currently underway.
- bool isFirstReflow = (mState & NS_FRAME_FIRST_REFLOW);
- bool outerSVGHasHadFirstReflow =
- (GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) == 0;
- if (outerSVGHasHadFirstReflow) {
- mState &= ~NS_FRAME_FIRST_REFLOW; // tell our children
- }
- nsOverflowAreas overflowRects;
- nsIFrame *child = GetActiveChildFrame();
- nsISVGChildFrame* svgChild = do_QueryFrame(child);
- if (svgChild) {
- MOZ_ASSERT(!(child->GetStateBits() & NS_FRAME_IS_NONDISPLAY),
- "Check for this explicitly in the |if|, then");
- svgChild->ReflowSVG();
- // We build up our child frame overflows here instead of using
- // nsLayoutUtils::UnionChildOverflow since SVG frame's all use the same
- // frame list, and we're iterating over that list now anyway.
- ConsiderChildOverflow(overflowRects, child);
- }
- if (isFirstReflow) {
- // Make sure we have our filter property (if any) before calling
- // FinishAndStoreOverflow (subsequent filter changes are handled off
- // nsChangeHint_UpdateEffects):
- nsSVGEffects::UpdateEffects(this);
- }
- FinishAndStoreOverflow(overflowRects, mRect.Size());
- // Remove state bits after FinishAndStoreOverflow so that it doesn't
- // invalidate on first reflow:
- mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
- NS_FRAME_HAS_DIRTY_CHILDREN);
- }
- SVGBBox
- nsSVGSwitchFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace,
- uint32_t aFlags)
- {
- nsIFrame* kid = GetActiveChildFrame();
- nsISVGChildFrame* svgKid = do_QueryFrame(kid);
- if (svgKid) {
- nsIContent *content = kid->GetContent();
- gfxMatrix transform = ThebesMatrix(aToBBoxUserspace);
- if (content->IsSVGElement()) {
- transform = static_cast<nsSVGElement*>(content)->
- PrependLocalTransformsTo(transform);
- }
- return svgKid->GetBBoxContribution(ToMatrix(transform), aFlags);
- }
- return SVGBBox();
- }
- nsIFrame *
- nsSVGSwitchFrame::GetActiveChildFrame()
- {
- nsIContent *activeChild =
- static_cast<mozilla::dom::SVGSwitchElement*>(mContent)->GetActiveChild();
- if (activeChild) {
- for (nsIFrame* kid = mFrames.FirstChild(); kid;
- kid = kid->GetNextSibling()) {
- if (activeChild == kid->GetContent()) {
- return kid;
- }
- }
- }
- return nullptr;
- }
|