void nsSVGInnerSVGFrame::NotifySVGChanged(uint32_t aFlags) { NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED), "Invalidation logic may need adjusting"); if (aFlags & COORD_CONTEXT_CHANGED) { SVGSVGElement *svg = static_cast<SVGSVGElement*>(mContent); bool xOrYIsPercentage = svg->mLengthAttributes[SVGSVGElement::ATTR_X].IsPercentage() || svg->mLengthAttributes[SVGSVGElement::ATTR_Y].IsPercentage(); bool widthOrHeightIsPercentage = svg->mLengthAttributes[SVGSVGElement::ATTR_WIDTH].IsPercentage() || svg->mLengthAttributes[SVGSVGElement::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; } nsSVGInnerSVGFrameBase::NotifySVGChanged(aFlags); }
void nsSVGOuterSVGFrame::NotifyViewportOrTransformChanged(uint32_t aFlags) { NS_ABORT_IF_FALSE(aFlags && !(aFlags & ~(COORD_CONTEXT_CHANGED | TRANSFORM_CHANGED | FULL_ZOOM_CHANGED)), "Unexpected aFlags value"); // No point in doing anything when were not init'ed yet: if (!mViewportInitialized) { return; } SVGSVGElement *content = static_cast<SVGSVGElement*>(mContent); if (aFlags & COORD_CONTEXT_CHANGED) { if (content->HasViewBoxRect()) { // Percentage lengths on children resolve against the viewBox rect so we // don't need to notify them of the viewport change, but the viewBox // transform will have changed, so we need to notify them of that instead. aFlags = TRANSFORM_CHANGED; } else if (content->ShouldSynthesizeViewBox()) { // In the case of a synthesized viewBox, the synthetic viewBox's rect // changes as the viewport changes. As a result we need to maintain the // COORD_CONTEXT_CHANGED flag. aFlags |= TRANSFORM_CHANGED; } else if (mCanvasTM && mCanvasTM->IsSingular()) { // A width/height of zero will result in us having a singular mCanvasTM // even when we don't have a viewBox. So we also want to recompute our // mCanvasTM for this width/height change even though we don't have a // viewBox. aFlags |= TRANSFORM_CHANGED; } } bool haveNonFulLZoomTransformChange = (aFlags & TRANSFORM_CHANGED); if (aFlags & FULL_ZOOM_CHANGED) { // Convert FULL_ZOOM_CHANGED to TRANSFORM_CHANGED: aFlags = (aFlags & ~FULL_ZOOM_CHANGED) | TRANSFORM_CHANGED; } if (aFlags & TRANSFORM_CHANGED) { // Make sure our canvas transform matrix gets (lazily) recalculated: mCanvasTM = nullptr; if (haveNonFulLZoomTransformChange && !(mState & NS_FRAME_IS_NONDISPLAY)) { uint32_t flags = (mState & NS_FRAME_IN_REFLOW) ? SVGSVGElement::eDuringReflow : 0; content->ChildrenOnlyTransformChanged(flags); } } nsSVGUtils::NotifyChildrenOfSVGChange(GetFirstPrincipalChild(), aFlags); }