tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SVGUseFrame.cpp (4939B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "SVGUseFrame.h"
      8 
      9 #include "mozilla/PresShell.h"
     10 #include "mozilla/SVGObserverUtils.h"
     11 #include "mozilla/SVGUtils.h"
     12 #include "mozilla/dom/SVGUseElement.h"
     13 #include "nsLayoutUtils.h"
     14 
     15 using namespace mozilla::dom;
     16 
     17 //----------------------------------------------------------------------
     18 // Implementation
     19 
     20 nsIFrame* NS_NewSVGUseFrame(mozilla::PresShell* aPresShell,
     21                            mozilla::ComputedStyle* aStyle) {
     22  return new (aPresShell)
     23      mozilla::SVGUseFrame(aStyle, aPresShell->GetPresContext());
     24 }
     25 
     26 namespace mozilla {
     27 
     28 NS_IMPL_FRAMEARENA_HELPERS(SVGUseFrame)
     29 
     30 //----------------------------------------------------------------------
     31 // nsIFrame methods:
     32 
     33 void SVGUseFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
     34                       nsIFrame* aPrevInFlow) {
     35  NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::use),
     36               "Content is not an SVG use!");
     37 
     38  mHasValidDimensions =
     39      static_cast<SVGUseElement*>(aContent)->HasValidDimensions();
     40 
     41  SVGGFrame::Init(aContent, aParent, aPrevInFlow);
     42 }
     43 
     44 void SVGUseFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
     45  SVGGFrame::DidSetComputedStyle(aOldComputedStyle);
     46 
     47  if (!aOldComputedStyle) {
     48    return;
     49  }
     50  const auto* newSVGReset = StyleSVGReset();
     51  const auto* oldSVGReset = aOldComputedStyle->StyleSVGReset();
     52 
     53  if (newSVGReset->mX != oldSVGReset->mX ||
     54      newSVGReset->mY != oldSVGReset->mY) {
     55    // make sure our cached transform matrix gets (lazily) updated
     56    mCanvasTM = nullptr;
     57    SVGUtils::ScheduleReflowSVG(this);
     58    SVGUtils::NotifyChildrenOfSVGChange(this, ChangeFlag::TransformChanged);
     59  }
     60 }
     61 
     62 void SVGUseFrame::DimensionAttributeChanged(bool aHadValidDimensions,
     63                                            bool aAttributeIsUsed) {
     64  bool invalidate = aAttributeIsUsed;
     65  if (mHasValidDimensions != aHadValidDimensions) {
     66    mHasValidDimensions = !mHasValidDimensions;
     67    invalidate = true;
     68  }
     69 
     70  if (invalidate) {
     71    nsLayoutUtils::PostRestyleEvent(GetContent()->AsElement(), RestyleHint{0},
     72                                    nsChangeHint_InvalidateRenderingObservers);
     73    SVGUtils::ScheduleReflowSVG(this);
     74  }
     75 }
     76 
     77 void SVGUseFrame::HrefChanged() {
     78  nsLayoutUtils::PostRestyleEvent(GetContent()->AsElement(), RestyleHint{0},
     79                                  nsChangeHint_InvalidateRenderingObservers);
     80  SVGUtils::ScheduleReflowSVG(this);
     81 }
     82 
     83 //----------------------------------------------------------------------
     84 // ISVGDisplayableFrame methods
     85 
     86 void SVGUseFrame::ReflowSVG() {
     87  // We only handle x/y offset here, since any width/height that is in force is
     88  // handled by the SVGOuterSVGFrame for the anonymous <svg> that will be
     89  // created for that purpose.
     90  auto* content = SVGUseElement::FromNode(GetContent());
     91  float x = SVGContentUtils::CoordToFloat(content, StyleSVGReset()->mX,
     92                                          SVGContentUtils::X);
     93  float y = SVGContentUtils::CoordToFloat(content, StyleSVGReset()->mY,
     94                                          SVGContentUtils::Y);
     95  mRect.MoveTo(nsLayoutUtils::RoundGfxRectToAppRect(gfxRect(x, y, 0, 0),
     96                                                    AppUnitsPerCSSPixel())
     97                   .TopLeft());
     98 
     99  // If we have a filter, we need to invalidate ourselves because filter
    100  // output can change even if none of our descendants need repainting.
    101  if (StyleEffects()->HasFilters()) {
    102    InvalidateFrame();
    103  }
    104 
    105  SVGGFrame::ReflowSVG();
    106 }
    107 
    108 void SVGUseFrame::NotifySVGChanged(ChangeFlags aFlags) {
    109  if (aFlags.contains(ChangeFlag::CoordContextChanged) &&
    110      !aFlags.contains(ChangeFlag::TransformChanged)) {
    111    // Coordinate context changes affect mCanvasTM if we have a
    112    // percentage 'x' or 'y'
    113    if (StyleSVGReset()->mX.HasPercent() || StyleSVGReset()->mY.HasPercent()) {
    114      aFlags += ChangeFlag::TransformChanged;
    115      // Ancestor changes can't affect how we render from the perspective of
    116      // any rendering observers that we may have, so we don't need to
    117      // invalidate them. We also don't need to invalidate ourself, since our
    118      // changed ancestor will have invalidated its entire area, which includes
    119      // our area.
    120      // For perf reasons we call this before calling NotifySVGChanged() below.
    121      SVGUtils::ScheduleReflowSVG(this);
    122    }
    123  }
    124 
    125  // We don't remove the TRANSFORM_CHANGED flag here if we have a viewBox or
    126  // non-percentage width/height, since if they're set then they are cloned to
    127  // an anonymous child <svg>, and its SVGInnerSVGFrame will do that.
    128 
    129  SVGGFrame::NotifySVGChanged(aFlags);
    130 }
    131 
    132 }  // namespace mozilla