layout/svg/nsSVGOuterSVGFrame.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 // Main header first:
michael@0 7 #include "nsSVGOuterSVGFrame.h"
michael@0 8
michael@0 9 // Keep others in (case-insensitive) order:
michael@0 10 #include "nsDisplayList.h"
michael@0 11 #include "nsIDocument.h"
michael@0 12 #include "nsIDOMWindow.h"
michael@0 13 #include "nsIInterfaceRequestorUtils.h"
michael@0 14 #include "nsIObjectLoadingContent.h"
michael@0 15 #include "nsRenderingContext.h"
michael@0 16 #include "nsSVGIntegrationUtils.h"
michael@0 17 #include "nsSVGForeignObjectFrame.h"
michael@0 18 #include "mozilla/dom/SVGSVGElement.h"
michael@0 19 #include "mozilla/dom/SVGViewElement.h"
michael@0 20 #include "nsSubDocumentFrame.h"
michael@0 21
michael@0 22 using namespace mozilla;
michael@0 23 using namespace mozilla::dom;
michael@0 24
michael@0 25 //----------------------------------------------------------------------
michael@0 26 // Implementation helpers
michael@0 27
michael@0 28 void
michael@0 29 nsSVGOuterSVGFrame::RegisterForeignObject(nsSVGForeignObjectFrame* aFrame)
michael@0 30 {
michael@0 31 NS_ASSERTION(aFrame, "Who on earth is calling us?!");
michael@0 32
michael@0 33 if (!mForeignObjectHash) {
michael@0 34 mForeignObjectHash = new nsTHashtable<nsPtrHashKey<nsSVGForeignObjectFrame> >();
michael@0 35 }
michael@0 36
michael@0 37 NS_ASSERTION(!mForeignObjectHash->GetEntry(aFrame),
michael@0 38 "nsSVGForeignObjectFrame already registered!");
michael@0 39
michael@0 40 mForeignObjectHash->PutEntry(aFrame);
michael@0 41
michael@0 42 NS_ASSERTION(mForeignObjectHash->GetEntry(aFrame),
michael@0 43 "Failed to register nsSVGForeignObjectFrame!");
michael@0 44 }
michael@0 45
michael@0 46 void
michael@0 47 nsSVGOuterSVGFrame::UnregisterForeignObject(nsSVGForeignObjectFrame* aFrame)
michael@0 48 {
michael@0 49 NS_ASSERTION(aFrame, "Who on earth is calling us?!");
michael@0 50 NS_ASSERTION(mForeignObjectHash && mForeignObjectHash->GetEntry(aFrame),
michael@0 51 "nsSVGForeignObjectFrame not in registry!");
michael@0 52 return mForeignObjectHash->RemoveEntry(aFrame);
michael@0 53 }
michael@0 54
michael@0 55 //----------------------------------------------------------------------
michael@0 56 // Implementation
michael@0 57
michael@0 58 nsIFrame*
michael@0 59 NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
michael@0 60 {
michael@0 61 return new (aPresShell) nsSVGOuterSVGFrame(aContext);
michael@0 62 }
michael@0 63
michael@0 64 NS_IMPL_FRAMEARENA_HELPERS(nsSVGOuterSVGFrame)
michael@0 65
michael@0 66 nsSVGOuterSVGFrame::nsSVGOuterSVGFrame(nsStyleContext* aContext)
michael@0 67 : nsSVGOuterSVGFrameBase(aContext)
michael@0 68 , mFullZoom(aContext->PresContext()->GetFullZoom())
michael@0 69 , mViewportInitialized(false)
michael@0 70 , mIsRootContent(false)
michael@0 71 {
michael@0 72 // Outer-<svg> has CSS layout, so remove this bit:
michael@0 73 RemoveStateBits(NS_FRAME_SVG_LAYOUT);
michael@0 74 }
michael@0 75
michael@0 76 void
michael@0 77 nsSVGOuterSVGFrame::Init(nsIContent* aContent,
michael@0 78 nsIFrame* aParent,
michael@0 79 nsIFrame* aPrevInFlow)
michael@0 80 {
michael@0 81 NS_ASSERTION(aContent->IsSVG(nsGkAtoms::svg),
michael@0 82 "Content is not an SVG 'svg' element!");
michael@0 83
michael@0 84 AddStateBits(NS_STATE_IS_OUTER_SVG |
michael@0 85 NS_FRAME_FONT_INFLATION_CONTAINER |
michael@0 86 NS_FRAME_FONT_INFLATION_FLOW_ROOT);
michael@0 87
michael@0 88 // Check for conditional processing attributes here rather than in
michael@0 89 // nsCSSFrameConstructor::FindSVGData because we want to avoid
michael@0 90 // simply giving failing outer <svg> elements an nsSVGContainerFrame.
michael@0 91 // We don't create other SVG frames if PassesConditionalProcessingTests
michael@0 92 // returns false, but since we do create nsSVGOuterSVGFrame frames we
michael@0 93 // prevent them from painting by [ab]use NS_FRAME_IS_NONDISPLAY. The
michael@0 94 // frame will be recreated via an nsChangeHint_ReconstructFrame restyle if
michael@0 95 // the value returned by PassesConditionalProcessingTests changes.
michael@0 96 SVGSVGElement *svg = static_cast<SVGSVGElement*>(aContent);
michael@0 97 if (!svg->PassesConditionalProcessingTests()) {
michael@0 98 AddStateBits(NS_FRAME_IS_NONDISPLAY);
michael@0 99 }
michael@0 100
michael@0 101 nsSVGOuterSVGFrameBase::Init(aContent, aParent, aPrevInFlow);
michael@0 102
michael@0 103 nsIDocument* doc = mContent->GetCurrentDoc();
michael@0 104 if (doc) {
michael@0 105 // we only care about our content's zoom and pan values if it's the root element
michael@0 106 if (doc->GetRootElement() == mContent) {
michael@0 107 mIsRootContent = true;
michael@0 108 }
michael@0 109 }
michael@0 110 }
michael@0 111
michael@0 112 //----------------------------------------------------------------------
michael@0 113 // nsQueryFrame methods
michael@0 114
michael@0 115 NS_QUERYFRAME_HEAD(nsSVGOuterSVGFrame)
michael@0 116 NS_QUERYFRAME_ENTRY(nsISVGSVGFrame)
michael@0 117 NS_QUERYFRAME_TAIL_INHERITING(nsSVGOuterSVGFrameBase)
michael@0 118
michael@0 119 //----------------------------------------------------------------------
michael@0 120 // nsIFrame methods
michael@0 121
michael@0 122 //----------------------------------------------------------------------
michael@0 123 // reflowing
michael@0 124
michael@0 125 /* virtual */ nscoord
michael@0 126 nsSVGOuterSVGFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
michael@0 127 {
michael@0 128 nscoord result;
michael@0 129 DISPLAY_MIN_WIDTH(this, result);
michael@0 130
michael@0 131 result = nscoord(0);
michael@0 132
michael@0 133 return result;
michael@0 134 }
michael@0 135
michael@0 136 /* virtual */ nscoord
michael@0 137 nsSVGOuterSVGFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
michael@0 138 {
michael@0 139 nscoord result;
michael@0 140 DISPLAY_PREF_WIDTH(this, result);
michael@0 141
michael@0 142 SVGSVGElement *svg = static_cast<SVGSVGElement*>(mContent);
michael@0 143 nsSVGLength2 &width = svg->mLengthAttributes[SVGSVGElement::ATTR_WIDTH];
michael@0 144
michael@0 145 if (width.IsPercentage()) {
michael@0 146 // It looks like our containing block's width may depend on our width. In
michael@0 147 // that case our behavior is undefined according to CSS 2.1 section 10.3.2,
michael@0 148 // so return zero.
michael@0 149 result = nscoord(0);
michael@0 150 } else {
michael@0 151 result = nsPresContext::CSSPixelsToAppUnits(width.GetAnimValue(svg));
michael@0 152 if (result < 0) {
michael@0 153 result = nscoord(0);
michael@0 154 }
michael@0 155 }
michael@0 156
michael@0 157 return result;
michael@0 158 }
michael@0 159
michael@0 160 /* virtual */ IntrinsicSize
michael@0 161 nsSVGOuterSVGFrame::GetIntrinsicSize()
michael@0 162 {
michael@0 163 // XXXjwatt Note that here we want to return the CSS width/height if they're
michael@0 164 // specified and we're embedded inside an nsIObjectLoadingContent.
michael@0 165
michael@0 166 IntrinsicSize intrinsicSize;
michael@0 167
michael@0 168 SVGSVGElement *content = static_cast<SVGSVGElement*>(mContent);
michael@0 169 nsSVGLength2 &width = content->mLengthAttributes[SVGSVGElement::ATTR_WIDTH];
michael@0 170 nsSVGLength2 &height = content->mLengthAttributes[SVGSVGElement::ATTR_HEIGHT];
michael@0 171
michael@0 172 if (!width.IsPercentage()) {
michael@0 173 nscoord val = nsPresContext::CSSPixelsToAppUnits(width.GetAnimValue(content));
michael@0 174 if (val < 0) val = 0;
michael@0 175 intrinsicSize.width.SetCoordValue(val);
michael@0 176 }
michael@0 177
michael@0 178 if (!height.IsPercentage()) {
michael@0 179 nscoord val = nsPresContext::CSSPixelsToAppUnits(height.GetAnimValue(content));
michael@0 180 if (val < 0) val = 0;
michael@0 181 intrinsicSize.height.SetCoordValue(val);
michael@0 182 }
michael@0 183
michael@0 184 return intrinsicSize;
michael@0 185 }
michael@0 186
michael@0 187 /* virtual */ nsSize
michael@0 188 nsSVGOuterSVGFrame::GetIntrinsicRatio()
michael@0 189 {
michael@0 190 // We only have an intrinsic size/ratio if our width and height attributes
michael@0 191 // are both specified and set to non-percentage values, or we have a viewBox
michael@0 192 // rect: http://www.w3.org/TR/SVGMobile12/coords.html#IntrinsicSizing
michael@0 193
michael@0 194 SVGSVGElement *content = static_cast<SVGSVGElement*>(mContent);
michael@0 195 nsSVGLength2 &width = content->mLengthAttributes[SVGSVGElement::ATTR_WIDTH];
michael@0 196 nsSVGLength2 &height = content->mLengthAttributes[SVGSVGElement::ATTR_HEIGHT];
michael@0 197
michael@0 198 if (!width.IsPercentage() && !height.IsPercentage()) {
michael@0 199 nsSize ratio(NSToCoordRoundWithClamp(width.GetAnimValue(content)),
michael@0 200 NSToCoordRoundWithClamp(height.GetAnimValue(content)));
michael@0 201 if (ratio.width < 0) {
michael@0 202 ratio.width = 0;
michael@0 203 }
michael@0 204 if (ratio.height < 0) {
michael@0 205 ratio.height = 0;
michael@0 206 }
michael@0 207 return ratio;
michael@0 208 }
michael@0 209
michael@0 210 SVGViewElement* viewElement = content->GetCurrentViewElement();
michael@0 211 const nsSVGViewBoxRect* viewbox = nullptr;
michael@0 212
michael@0 213 // The logic here should match HasViewBox().
michael@0 214 if (viewElement && viewElement->mViewBox.HasRect()) {
michael@0 215 viewbox = &viewElement->mViewBox.GetAnimValue();
michael@0 216 } else if (content->mViewBox.HasRect()) {
michael@0 217 viewbox = &content->mViewBox.GetAnimValue();
michael@0 218 }
michael@0 219
michael@0 220 if (viewbox) {
michael@0 221 float viewBoxWidth = viewbox->width;
michael@0 222 float viewBoxHeight = viewbox->height;
michael@0 223
michael@0 224 if (viewBoxWidth < 0.0f) {
michael@0 225 viewBoxWidth = 0.0f;
michael@0 226 }
michael@0 227 if (viewBoxHeight < 0.0f) {
michael@0 228 viewBoxHeight = 0.0f;
michael@0 229 }
michael@0 230 return nsSize(NSToCoordRoundWithClamp(viewBoxWidth),
michael@0 231 NSToCoordRoundWithClamp(viewBoxHeight));
michael@0 232 }
michael@0 233
michael@0 234 return nsSVGOuterSVGFrameBase::GetIntrinsicRatio();
michael@0 235 }
michael@0 236
michael@0 237 /* virtual */ nsSize
michael@0 238 nsSVGOuterSVGFrame::ComputeSize(nsRenderingContext *aRenderingContext,
michael@0 239 nsSize aCBSize, nscoord aAvailableWidth,
michael@0 240 nsSize aMargin, nsSize aBorder, nsSize aPadding,
michael@0 241 uint32_t aFlags)
michael@0 242 {
michael@0 243 if (IsRootOfImage() || IsRootOfReplacedElementSubDoc()) {
michael@0 244 // The embedding element has sized itself using the CSS replaced element
michael@0 245 // sizing rules, using our intrinsic dimensions as necessary. The SVG spec
michael@0 246 // says that the width and height of embedded SVG is overridden by the
michael@0 247 // width and height of the embedding element, so we just need to size to
michael@0 248 // the viewport that the embedding element has established for us.
michael@0 249 return aCBSize;
michael@0 250 }
michael@0 251
michael@0 252 nsSize cbSize = aCBSize;
michael@0 253 IntrinsicSize intrinsicSize = GetIntrinsicSize();
michael@0 254
michael@0 255 if (!mContent->GetParent()) {
michael@0 256 // We're the root of the outermost browsing context, so we need to scale
michael@0 257 // cbSize by the full-zoom so that SVGs with percentage width/height zoom:
michael@0 258
michael@0 259 NS_ASSERTION(aCBSize.width != NS_AUTOHEIGHT &&
michael@0 260 aCBSize.height != NS_AUTOHEIGHT,
michael@0 261 "root should not have auto-width/height containing block");
michael@0 262 cbSize.width *= PresContext()->GetFullZoom();
michael@0 263 cbSize.height *= PresContext()->GetFullZoom();
michael@0 264
michael@0 265 // We also need to honour the width and height attributes' default values
michael@0 266 // of 100% when we're the root of a browsing context. (GetIntrinsicSize()
michael@0 267 // doesn't report these since there's no such thing as a percentage
michael@0 268 // intrinsic size. Also note that explicit percentage values are mapped
michael@0 269 // into style, so the following isn't for them.)
michael@0 270
michael@0 271 SVGSVGElement* content = static_cast<SVGSVGElement*>(mContent);
michael@0 272
michael@0 273 nsSVGLength2 &width =
michael@0 274 content->mLengthAttributes[SVGSVGElement::ATTR_WIDTH];
michael@0 275 if (width.IsPercentage()) {
michael@0 276 NS_ABORT_IF_FALSE(intrinsicSize.width.GetUnit() == eStyleUnit_None,
michael@0 277 "GetIntrinsicSize should have reported no "
michael@0 278 "intrinsic width");
michael@0 279 float val = width.GetAnimValInSpecifiedUnits() / 100.0f;
michael@0 280 if (val < 0.0f) val = 0.0f;
michael@0 281 intrinsicSize.width.SetCoordValue(val * cbSize.width);
michael@0 282 }
michael@0 283
michael@0 284 nsSVGLength2 &height =
michael@0 285 content->mLengthAttributes[SVGSVGElement::ATTR_HEIGHT];
michael@0 286 NS_ASSERTION(aCBSize.height != NS_AUTOHEIGHT,
michael@0 287 "root should not have auto-height containing block");
michael@0 288 if (height.IsPercentage()) {
michael@0 289 NS_ABORT_IF_FALSE(intrinsicSize.height.GetUnit() == eStyleUnit_None,
michael@0 290 "GetIntrinsicSize should have reported no "
michael@0 291 "intrinsic height");
michael@0 292 float val = height.GetAnimValInSpecifiedUnits() / 100.0f;
michael@0 293 if (val < 0.0f) val = 0.0f;
michael@0 294 intrinsicSize.height.SetCoordValue(val * cbSize.height);
michael@0 295 }
michael@0 296 NS_ABORT_IF_FALSE(intrinsicSize.height.GetUnit() == eStyleUnit_Coord &&
michael@0 297 intrinsicSize.width.GetUnit() == eStyleUnit_Coord,
michael@0 298 "We should have just handled the only situation where"
michael@0 299 "we lack an intrinsic height or width.");
michael@0 300 }
michael@0 301
michael@0 302 return nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(
michael@0 303 aRenderingContext, this,
michael@0 304 intrinsicSize, GetIntrinsicRatio(), cbSize,
michael@0 305 aMargin, aBorder, aPadding);
michael@0 306 }
michael@0 307
michael@0 308 nsresult
michael@0 309 nsSVGOuterSVGFrame::Reflow(nsPresContext* aPresContext,
michael@0 310 nsHTMLReflowMetrics& aDesiredSize,
michael@0 311 const nsHTMLReflowState& aReflowState,
michael@0 312 nsReflowStatus& aStatus)
michael@0 313 {
michael@0 314 DO_GLOBAL_REFLOW_COUNT("nsSVGOuterSVGFrame");
michael@0 315 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
michael@0 316 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
michael@0 317 ("enter nsSVGOuterSVGFrame::Reflow: availSize=%d,%d",
michael@0 318 aReflowState.AvailableWidth(), aReflowState.AvailableHeight()));
michael@0 319
michael@0 320 NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow");
michael@0 321
michael@0 322 aStatus = NS_FRAME_COMPLETE;
michael@0 323
michael@0 324 aDesiredSize.Width() = aReflowState.ComputedWidth() +
michael@0 325 aReflowState.ComputedPhysicalBorderPadding().LeftRight();
michael@0 326 aDesiredSize.Height() = aReflowState.ComputedHeight() +
michael@0 327 aReflowState.ComputedPhysicalBorderPadding().TopBottom();
michael@0 328
michael@0 329 NS_ASSERTION(!GetPrevInFlow(), "SVG can't currently be broken across pages.");
michael@0 330
michael@0 331 SVGSVGElement *svgElem = static_cast<SVGSVGElement*>(mContent);
michael@0 332
michael@0 333 nsSVGOuterSVGAnonChildFrame *anonKid =
michael@0 334 static_cast<nsSVGOuterSVGAnonChildFrame*>(GetFirstPrincipalChild());
michael@0 335
michael@0 336 if (mState & NS_FRAME_FIRST_REFLOW) {
michael@0 337 // Initialize
michael@0 338 svgElem->UpdateHasChildrenOnlyTransform();
michael@0 339 }
michael@0 340
michael@0 341 // If our SVG viewport has changed, update our content and notify.
michael@0 342 // http://www.w3.org/TR/SVG11/coords.html#ViewportSpace
michael@0 343
michael@0 344 svgFloatSize newViewportSize(
michael@0 345 nsPresContext::AppUnitsToFloatCSSPixels(aReflowState.ComputedWidth()),
michael@0 346 nsPresContext::AppUnitsToFloatCSSPixels(aReflowState.ComputedHeight()));
michael@0 347
michael@0 348 svgFloatSize oldViewportSize = svgElem->GetViewportSize();
michael@0 349
michael@0 350 uint32_t changeBits = 0;
michael@0 351 if (newViewportSize != oldViewportSize) {
michael@0 352 // When our viewport size changes, we may need to update the overflow rects
michael@0 353 // of our child frames. This is the case if:
michael@0 354 //
michael@0 355 // * We have a real/synthetic viewBox (a children-only transform), since
michael@0 356 // the viewBox transform will change as the viewport dimensions change.
michael@0 357 //
michael@0 358 // * We do not have a real/synthetic viewBox, but the last time we
michael@0 359 // reflowed (or the last time UpdateOverflow() was called) we did.
michael@0 360 //
michael@0 361 // We only handle the former case here, in which case we mark all our child
michael@0 362 // frames as dirty so that we reflow them below and update their overflow
michael@0 363 // rects.
michael@0 364 //
michael@0 365 // In the latter case, updating of overflow rects is handled for removal of
michael@0 366 // real viewBox (the viewBox attribute) in AttributeChanged. Synthetic
michael@0 367 // viewBox "removal" (e.g. a document references the same SVG via both an
michael@0 368 // <svg:image> and then as a CSS background image (a synthetic viewBox is
michael@0 369 // used when painting the former, but not when painting the latter)) is
michael@0 370 // handled in SVGSVGElement::FlushImageTransformInvalidation.
michael@0 371 //
michael@0 372 if (svgElem->HasViewBoxOrSyntheticViewBox()) {
michael@0 373 nsIFrame* anonChild = GetFirstPrincipalChild();
michael@0 374 anonChild->AddStateBits(NS_FRAME_IS_DIRTY);
michael@0 375 for (nsIFrame* child = anonChild->GetFirstPrincipalChild(); child;
michael@0 376 child = child->GetNextSibling()) {
michael@0 377 child->AddStateBits(NS_FRAME_IS_DIRTY);
michael@0 378 }
michael@0 379 }
michael@0 380 changeBits |= COORD_CONTEXT_CHANGED;
michael@0 381 svgElem->SetViewportSize(newViewportSize);
michael@0 382 }
michael@0 383 if (mFullZoom != PresContext()->GetFullZoom()) {
michael@0 384 changeBits |= FULL_ZOOM_CHANGED;
michael@0 385 mFullZoom = PresContext()->GetFullZoom();
michael@0 386 }
michael@0 387 if (changeBits) {
michael@0 388 NotifyViewportOrTransformChanged(changeBits);
michael@0 389 }
michael@0 390 mViewportInitialized = true;
michael@0 391
michael@0 392 // Now that we've marked the necessary children as dirty, call
michael@0 393 // ReflowSVG() or ReflowSVGNonDisplayText() on them, depending
michael@0 394 // on whether we are non-display.
michael@0 395 mCallingReflowSVG = true;
michael@0 396 if (GetStateBits() & NS_FRAME_IS_NONDISPLAY) {
michael@0 397 ReflowSVGNonDisplayText(this);
michael@0 398 } else {
michael@0 399 // Update the mRects and visual overflow rects of all our descendants,
michael@0 400 // including our anonymous wrapper kid:
michael@0 401 anonKid->AddStateBits(mState & NS_FRAME_IS_DIRTY);
michael@0 402 anonKid->ReflowSVG();
michael@0 403 NS_ABORT_IF_FALSE(!anonKid->GetNextSibling(),
michael@0 404 "We should have one anonymous child frame wrapping our real children");
michael@0 405 }
michael@0 406 mCallingReflowSVG = false;
michael@0 407
michael@0 408 // Set our anonymous kid's offset from our border box:
michael@0 409 anonKid->SetPosition(GetContentRectRelativeToSelf().TopLeft());
michael@0 410
michael@0 411 // Including our size in our overflow rects regardless of the value of
michael@0 412 // 'background', 'border', etc. makes sure that we usually (when we clip to
michael@0 413 // our content area) don't have to keep changing our overflow rects as our
michael@0 414 // descendants move about (see perf comment below). Including our size in our
michael@0 415 // scrollable overflow rect also makes sure that we scroll if we're too big
michael@0 416 // for our viewport.
michael@0 417 //
michael@0 418 // <svg> never allows scrolling to anything outside its mRect (only panning),
michael@0 419 // so we must always keep our scrollable overflow set to our size.
michael@0 420 //
michael@0 421 // With regards to visual overflow, we always clip root-<svg> (see our
michael@0 422 // BuildDisplayList method) regardless of the value of the 'overflow'
michael@0 423 // property since that is per-spec, even for the initial 'visible' value. For
michael@0 424 // that reason there's no point in adding descendant visual overflow to our
michael@0 425 // own when this frame is for a root-<svg>. That said, there's also a very
michael@0 426 // good performance reason for us wanting to avoid doing so. If we did, then
michael@0 427 // the frame's overflow would often change as descendants that are partially
michael@0 428 // or fully outside its rect moved (think animation on/off screen), and that
michael@0 429 // would cause us to do a full NS_FRAME_IS_DIRTY reflow and repaint of the
michael@0 430 // entire document tree each such move (see bug 875175).
michael@0 431 //
michael@0 432 // So it's only non-root outer-<svg> that has the visual overflow of its
michael@0 433 // descendants added to its own. (Note that the default user-agent style
michael@0 434 // sheet makes 'hidden' the default value for :not(root(svg)), so usually
michael@0 435 // FinishAndStoreOverflow will still clip this back to the frame's rect.)
michael@0 436 //
michael@0 437 // WARNING!! Keep UpdateBounds below in sync with whatever we do for our
michael@0 438 // overflow rects here! (Again, see bug 875175.)
michael@0 439 //
michael@0 440 aDesiredSize.SetOverflowAreasToDesiredBounds();
michael@0 441 if (!mIsRootContent) {
michael@0 442 aDesiredSize.mOverflowAreas.VisualOverflow().UnionRect(
michael@0 443 aDesiredSize.mOverflowAreas.VisualOverflow(),
michael@0 444 anonKid->GetVisualOverflowRect() + anonKid->GetPosition());
michael@0 445 }
michael@0 446 FinishAndStoreOverflow(&aDesiredSize);
michael@0 447
michael@0 448 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
michael@0 449 ("exit nsSVGOuterSVGFrame::Reflow: size=%d,%d",
michael@0 450 aDesiredSize.Width(), aDesiredSize.Height()));
michael@0 451 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
michael@0 452 return NS_OK;
michael@0 453 }
michael@0 454
michael@0 455 nsresult
michael@0 456 nsSVGOuterSVGFrame::DidReflow(nsPresContext* aPresContext,
michael@0 457 const nsHTMLReflowState* aReflowState,
michael@0 458 nsDidReflowStatus aStatus)
michael@0 459 {
michael@0 460 nsresult rv = nsSVGOuterSVGFrameBase::DidReflow(aPresContext,aReflowState,aStatus);
michael@0 461
michael@0 462 // Make sure elements styled by :hover get updated if script/animation moves
michael@0 463 // them under or out from under the pointer:
michael@0 464 PresContext()->PresShell()->SynthesizeMouseMove(false);
michael@0 465
michael@0 466 return rv;
michael@0 467 }
michael@0 468
michael@0 469 /* virtual */ bool
michael@0 470 nsSVGOuterSVGFrame::UpdateOverflow()
michael@0 471 {
michael@0 472 // See the comments in Reflow above.
michael@0 473
michael@0 474 // WARNING!! Keep this in sync with Reflow above!
michael@0 475
michael@0 476 nsRect rect(nsPoint(0, 0), GetSize());
michael@0 477 nsOverflowAreas overflowAreas(rect, rect);
michael@0 478
michael@0 479 if (!mIsRootContent) {
michael@0 480 nsIFrame *anonKid = GetFirstPrincipalChild();
michael@0 481 overflowAreas.VisualOverflow().UnionRect(
michael@0 482 overflowAreas.VisualOverflow(),
michael@0 483 anonKid->GetVisualOverflowRect() + anonKid->GetPosition());
michael@0 484 }
michael@0 485
michael@0 486 return FinishAndStoreOverflow(overflowAreas, GetSize());
michael@0 487 }
michael@0 488
michael@0 489
michael@0 490 //----------------------------------------------------------------------
michael@0 491 // container methods
michael@0 492
michael@0 493 /**
michael@0 494 * Used to paint/hit-test SVG when SVG display lists are disabled.
michael@0 495 */
michael@0 496 class nsDisplayOuterSVG : public nsDisplayItem {
michael@0 497 public:
michael@0 498 nsDisplayOuterSVG(nsDisplayListBuilder* aBuilder,
michael@0 499 nsSVGOuterSVGFrame* aFrame) :
michael@0 500 nsDisplayItem(aBuilder, aFrame) {
michael@0 501 MOZ_COUNT_CTOR(nsDisplayOuterSVG);
michael@0 502 }
michael@0 503 #ifdef NS_BUILD_REFCNT_LOGGING
michael@0 504 virtual ~nsDisplayOuterSVG() {
michael@0 505 MOZ_COUNT_DTOR(nsDisplayOuterSVG);
michael@0 506 }
michael@0 507 #endif
michael@0 508
michael@0 509 virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
michael@0 510 HitTestState* aState,
michael@0 511 nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE;
michael@0 512 virtual void Paint(nsDisplayListBuilder* aBuilder,
michael@0 513 nsRenderingContext* aCtx) MOZ_OVERRIDE;
michael@0 514
michael@0 515 virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
michael@0 516 const nsDisplayItemGeometry* aGeometry,
michael@0 517 nsRegion* aInvalidRegion) MOZ_OVERRIDE;
michael@0 518
michael@0 519 NS_DISPLAY_DECL_NAME("SVGOuterSVG", TYPE_SVG_OUTER_SVG)
michael@0 520 };
michael@0 521
michael@0 522 void
michael@0 523 nsDisplayOuterSVG::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
michael@0 524 HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
michael@0 525 {
michael@0 526 nsSVGOuterSVGFrame *outerSVGFrame = static_cast<nsSVGOuterSVGFrame*>(mFrame);
michael@0 527 nsRect rectAtOrigin = aRect - ToReferenceFrame();
michael@0 528 nsRect thisRect(nsPoint(0,0), outerSVGFrame->GetSize());
michael@0 529 if (!thisRect.Intersects(rectAtOrigin))
michael@0 530 return;
michael@0 531
michael@0 532 nsPoint rectCenter(rectAtOrigin.x + rectAtOrigin.width / 2,
michael@0 533 rectAtOrigin.y + rectAtOrigin.height / 2);
michael@0 534
michael@0 535 nsSVGOuterSVGAnonChildFrame *anonKid =
michael@0 536 static_cast<nsSVGOuterSVGAnonChildFrame*>(
michael@0 537 outerSVGFrame->GetFirstPrincipalChild());
michael@0 538 nsIFrame* frame = nsSVGUtils::HitTestChildren(
michael@0 539 anonKid, rectCenter + outerSVGFrame->GetPosition() -
michael@0 540 outerSVGFrame->GetContentRect().TopLeft());
michael@0 541 if (frame) {
michael@0 542 aOutFrames->AppendElement(frame);
michael@0 543 }
michael@0 544 }
michael@0 545
michael@0 546 void
michael@0 547 nsDisplayOuterSVG::Paint(nsDisplayListBuilder* aBuilder,
michael@0 548 nsRenderingContext* aContext)
michael@0 549 {
michael@0 550 #if defined(DEBUG) && defined(SVG_DEBUG_PAINT_TIMING)
michael@0 551 PRTime start = PR_Now();
michael@0 552 #endif
michael@0 553
michael@0 554 // Create an SVGAutoRenderState so we can call SetPaintingToWindow on
michael@0 555 // it, but do so without changing the render mode:
michael@0 556 SVGAutoRenderState state(aContext, SVGAutoRenderState::GetRenderMode(aContext));
michael@0 557
michael@0 558 if (aBuilder->IsPaintingToWindow()) {
michael@0 559 state.SetPaintingToWindow(true);
michael@0 560 }
michael@0 561
michael@0 562 nsRect viewportRect =
michael@0 563 mFrame->GetContentRectRelativeToSelf() + ToReferenceFrame();
michael@0 564
michael@0 565 nsRect clipRect = mVisibleRect.Intersect(viewportRect);
michael@0 566
michael@0 567 nsIntRect contentAreaDirtyRect =
michael@0 568 (clipRect - viewportRect.TopLeft()).
michael@0 569 ToOutsidePixels(mFrame->PresContext()->AppUnitsPerDevPixel());
michael@0 570
michael@0 571 aContext->PushState();
michael@0 572 aContext->Translate(viewportRect.TopLeft());
michael@0 573 nsSVGUtils::PaintFrameWithEffects(aContext, &contentAreaDirtyRect, mFrame);
michael@0 574 aContext->PopState();
michael@0 575
michael@0 576 NS_ASSERTION(!aContext->ThebesContext()->HasError(), "Cairo in error state");
michael@0 577
michael@0 578 #if defined(DEBUG) && defined(SVG_DEBUG_PAINT_TIMING)
michael@0 579 PRTime end = PR_Now();
michael@0 580 printf("SVG Paint Timing: %f ms\n", (end-start)/1000.0);
michael@0 581 #endif
michael@0 582 }
michael@0 583
michael@0 584 static PLDHashOperator CheckForeignObjectInvalidatedArea(nsPtrHashKey<nsSVGForeignObjectFrame>* aEntry, void* aData)
michael@0 585 {
michael@0 586 nsRegion* region = static_cast<nsRegion*>(aData);
michael@0 587 region->Or(*region, aEntry->GetKey()->GetInvalidRegion());
michael@0 588 return PL_DHASH_NEXT;
michael@0 589 }
michael@0 590
michael@0 591 nsRegion
michael@0 592 nsSVGOuterSVGFrame::FindInvalidatedForeignObjectFrameChildren(nsIFrame* aFrame)
michael@0 593 {
michael@0 594 nsRegion result;
michael@0 595 if (mForeignObjectHash && mForeignObjectHash->Count()) {
michael@0 596 mForeignObjectHash->EnumerateEntries(CheckForeignObjectInvalidatedArea, &result);
michael@0 597 }
michael@0 598 return result;
michael@0 599 }
michael@0 600
michael@0 601 void
michael@0 602 nsDisplayOuterSVG::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
michael@0 603 const nsDisplayItemGeometry* aGeometry,
michael@0 604 nsRegion* aInvalidRegion)
michael@0 605 {
michael@0 606 nsSVGOuterSVGFrame *frame = static_cast<nsSVGOuterSVGFrame*>(mFrame);
michael@0 607 frame->InvalidateSVG(frame->FindInvalidatedForeignObjectFrameChildren(frame));
michael@0 608
michael@0 609 nsRegion result = frame->GetInvalidRegion();
michael@0 610 result.MoveBy(ToReferenceFrame());
michael@0 611 frame->ClearInvalidRegion();
michael@0 612
michael@0 613 nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
michael@0 614 aInvalidRegion->Or(*aInvalidRegion, result);
michael@0 615 }
michael@0 616
michael@0 617 // helper
michael@0 618 static inline bool
michael@0 619 DependsOnIntrinsicSize(const nsIFrame* aEmbeddingFrame)
michael@0 620 {
michael@0 621 const nsStylePosition *pos = aEmbeddingFrame->StylePosition();
michael@0 622 const nsStyleCoord &width = pos->mWidth;
michael@0 623 const nsStyleCoord &height = pos->mHeight;
michael@0 624
michael@0 625 // XXX it would be nice to know if the size of aEmbeddingFrame's containing
michael@0 626 // block depends on aEmbeddingFrame, then we'd know if we can return false
michael@0 627 // for eStyleUnit_Percent too.
michael@0 628 return !width.ConvertsToLength() ||
michael@0 629 !height.ConvertsToLength();
michael@0 630 }
michael@0 631
michael@0 632 nsresult
michael@0 633 nsSVGOuterSVGFrame::AttributeChanged(int32_t aNameSpaceID,
michael@0 634 nsIAtom* aAttribute,
michael@0 635 int32_t aModType)
michael@0 636 {
michael@0 637 if (aNameSpaceID == kNameSpaceID_None &&
michael@0 638 !(GetStateBits() & (NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_NONDISPLAY))) {
michael@0 639 if (aAttribute == nsGkAtoms::viewBox ||
michael@0 640 aAttribute == nsGkAtoms::preserveAspectRatio ||
michael@0 641 aAttribute == nsGkAtoms::transform) {
michael@0 642
michael@0 643 // make sure our cached transform matrix gets (lazily) updated
michael@0 644 mCanvasTM = nullptr;
michael@0 645
michael@0 646 nsSVGUtils::NotifyChildrenOfSVGChange(GetFirstPrincipalChild(),
michael@0 647 aAttribute == nsGkAtoms::viewBox ?
michael@0 648 TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED : TRANSFORM_CHANGED);
michael@0 649
michael@0 650 if (aAttribute != nsGkAtoms::transform) {
michael@0 651 static_cast<SVGSVGElement*>(mContent)->ChildrenOnlyTransformChanged();
michael@0 652 }
michael@0 653
michael@0 654 } else if (aAttribute == nsGkAtoms::width ||
michael@0 655 aAttribute == nsGkAtoms::height) {
michael@0 656
michael@0 657 // Don't call ChildrenOnlyTransformChanged() here, since we call it
michael@0 658 // under Reflow if the width/height actually changed.
michael@0 659
michael@0 660 nsIFrame* embeddingFrame;
michael@0 661 if (IsRootOfReplacedElementSubDoc(&embeddingFrame) && embeddingFrame) {
michael@0 662 if (DependsOnIntrinsicSize(embeddingFrame)) {
michael@0 663 // Tell embeddingFrame's presShell it needs to be reflowed (which takes
michael@0 664 // care of reflowing us too).
michael@0 665 embeddingFrame->PresContext()->PresShell()->
michael@0 666 FrameNeedsReflow(embeddingFrame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
michael@0 667 }
michael@0 668 // else our width and height is overridden - don't reflow anything
michael@0 669 } else {
michael@0 670 // We are not embedded by reference, so our 'width' and 'height'
michael@0 671 // attributes are not overridden - we need to reflow.
michael@0 672 PresContext()->PresShell()->
michael@0 673 FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
michael@0 674 }
michael@0 675 }
michael@0 676 }
michael@0 677
michael@0 678 return NS_OK;
michael@0 679 }
michael@0 680
michael@0 681 //----------------------------------------------------------------------
michael@0 682 // painting
michael@0 683
michael@0 684 void
michael@0 685 nsSVGOuterSVGFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
michael@0 686 const nsRect& aDirtyRect,
michael@0 687 const nsDisplayListSet& aLists)
michael@0 688 {
michael@0 689 if (GetStateBits() & NS_FRAME_IS_NONDISPLAY) {
michael@0 690 return;
michael@0 691 }
michael@0 692
michael@0 693 DisplayBorderBackgroundOutline(aBuilder, aLists);
michael@0 694
michael@0 695 // Per-spec, we always clip root-<svg> even when 'overflow' has its initial
michael@0 696 // value of 'visible'. See also the "visual overflow" comments in Reflow.
michael@0 697 DisplayListClipState::AutoSaveRestore autoSR(aBuilder);
michael@0 698 if (mIsRootContent ||
michael@0 699 StyleDisplay()->IsScrollableOverflow()) {
michael@0 700 autoSR.ClipContainingBlockDescendantsToContentBox(aBuilder, this);
michael@0 701 }
michael@0 702
michael@0 703 if ((aBuilder->IsForEventDelivery() &&
michael@0 704 NS_SVGDisplayListHitTestingEnabled()) ||
michael@0 705 NS_SVGDisplayListPaintingEnabled()) {
michael@0 706 nsDisplayList *contentList = aLists.Content();
michael@0 707 nsDisplayListSet set(contentList, contentList, contentList,
michael@0 708 contentList, contentList, contentList);
michael@0 709 BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, set);
michael@0 710 } else {
michael@0 711 aLists.Content()->AppendNewToTop(
michael@0 712 new (aBuilder) nsDisplayOuterSVG(aBuilder, this));
michael@0 713 }
michael@0 714 }
michael@0 715
michael@0 716 nsSplittableType
michael@0 717 nsSVGOuterSVGFrame::GetSplittableType() const
michael@0 718 {
michael@0 719 return NS_FRAME_NOT_SPLITTABLE;
michael@0 720 }
michael@0 721
michael@0 722 nsIAtom *
michael@0 723 nsSVGOuterSVGFrame::GetType() const
michael@0 724 {
michael@0 725 return nsGkAtoms::svgOuterSVGFrame;
michael@0 726 }
michael@0 727
michael@0 728 //----------------------------------------------------------------------
michael@0 729 // nsISVGSVGFrame methods:
michael@0 730
michael@0 731 void
michael@0 732 nsSVGOuterSVGFrame::NotifyViewportOrTransformChanged(uint32_t aFlags)
michael@0 733 {
michael@0 734 NS_ABORT_IF_FALSE(aFlags &&
michael@0 735 !(aFlags & ~(COORD_CONTEXT_CHANGED | TRANSFORM_CHANGED |
michael@0 736 FULL_ZOOM_CHANGED)),
michael@0 737 "Unexpected aFlags value");
michael@0 738
michael@0 739 // No point in doing anything when were not init'ed yet:
michael@0 740 if (!mViewportInitialized) {
michael@0 741 return;
michael@0 742 }
michael@0 743
michael@0 744 SVGSVGElement *content = static_cast<SVGSVGElement*>(mContent);
michael@0 745
michael@0 746 if (aFlags & COORD_CONTEXT_CHANGED) {
michael@0 747 if (content->HasViewBoxRect()) {
michael@0 748 // Percentage lengths on children resolve against the viewBox rect so we
michael@0 749 // don't need to notify them of the viewport change, but the viewBox
michael@0 750 // transform will have changed, so we need to notify them of that instead.
michael@0 751 aFlags = TRANSFORM_CHANGED;
michael@0 752 }
michael@0 753 else if (content->ShouldSynthesizeViewBox()) {
michael@0 754 // In the case of a synthesized viewBox, the synthetic viewBox's rect
michael@0 755 // changes as the viewport changes. As a result we need to maintain the
michael@0 756 // COORD_CONTEXT_CHANGED flag.
michael@0 757 aFlags |= TRANSFORM_CHANGED;
michael@0 758 }
michael@0 759 else if (mCanvasTM && mCanvasTM->IsSingular()) {
michael@0 760 // A width/height of zero will result in us having a singular mCanvasTM
michael@0 761 // even when we don't have a viewBox. So we also want to recompute our
michael@0 762 // mCanvasTM for this width/height change even though we don't have a
michael@0 763 // viewBox.
michael@0 764 aFlags |= TRANSFORM_CHANGED;
michael@0 765 }
michael@0 766 }
michael@0 767
michael@0 768 bool haveNonFulLZoomTransformChange = (aFlags & TRANSFORM_CHANGED);
michael@0 769
michael@0 770 if (aFlags & FULL_ZOOM_CHANGED) {
michael@0 771 // Convert FULL_ZOOM_CHANGED to TRANSFORM_CHANGED:
michael@0 772 aFlags = (aFlags & ~FULL_ZOOM_CHANGED) | TRANSFORM_CHANGED;
michael@0 773 }
michael@0 774
michael@0 775 if (aFlags & TRANSFORM_CHANGED) {
michael@0 776 // Make sure our canvas transform matrix gets (lazily) recalculated:
michael@0 777 mCanvasTM = nullptr;
michael@0 778
michael@0 779 if (haveNonFulLZoomTransformChange &&
michael@0 780 !(mState & NS_FRAME_IS_NONDISPLAY)) {
michael@0 781 uint32_t flags = (mState & NS_FRAME_IN_REFLOW) ?
michael@0 782 SVGSVGElement::eDuringReflow : 0;
michael@0 783 content->ChildrenOnlyTransformChanged(flags);
michael@0 784 }
michael@0 785 }
michael@0 786
michael@0 787 nsSVGUtils::NotifyChildrenOfSVGChange(GetFirstPrincipalChild(), aFlags);
michael@0 788 }
michael@0 789
michael@0 790 //----------------------------------------------------------------------
michael@0 791 // nsISVGChildFrame methods:
michael@0 792
michael@0 793 nsresult
michael@0 794 nsSVGOuterSVGFrame::PaintSVG(nsRenderingContext* aContext,
michael@0 795 const nsIntRect *aDirtyRect,
michael@0 796 nsIFrame* aTransformRoot)
michael@0 797 {
michael@0 798 NS_ASSERTION(GetFirstPrincipalChild()->GetType() ==
michael@0 799 nsGkAtoms::svgOuterSVGAnonChildFrame &&
michael@0 800 !GetFirstPrincipalChild()->GetNextSibling(),
michael@0 801 "We should have a single, anonymous, child");
michael@0 802 nsSVGOuterSVGAnonChildFrame *anonKid =
michael@0 803 static_cast<nsSVGOuterSVGAnonChildFrame*>(GetFirstPrincipalChild());
michael@0 804 return anonKid->PaintSVG(aContext, aDirtyRect, aTransformRoot);
michael@0 805 }
michael@0 806
michael@0 807 SVGBBox
michael@0 808 nsSVGOuterSVGFrame::GetBBoxContribution(const gfx::Matrix &aToBBoxUserspace,
michael@0 809 uint32_t aFlags)
michael@0 810 {
michael@0 811 NS_ASSERTION(GetFirstPrincipalChild()->GetType() ==
michael@0 812 nsGkAtoms::svgOuterSVGAnonChildFrame &&
michael@0 813 !GetFirstPrincipalChild()->GetNextSibling(),
michael@0 814 "We should have a single, anonymous, child");
michael@0 815 // We must defer to our child so that we don't include our
michael@0 816 // content->PrependLocalTransformsTo() transforms.
michael@0 817 nsSVGOuterSVGAnonChildFrame *anonKid =
michael@0 818 static_cast<nsSVGOuterSVGAnonChildFrame*>(GetFirstPrincipalChild());
michael@0 819 return anonKid->GetBBoxContribution(aToBBoxUserspace, aFlags);
michael@0 820 }
michael@0 821
michael@0 822 //----------------------------------------------------------------------
michael@0 823 // nsSVGContainerFrame methods:
michael@0 824
michael@0 825 gfxMatrix
michael@0 826 nsSVGOuterSVGFrame::GetCanvasTM(uint32_t aFor, nsIFrame* aTransformRoot)
michael@0 827 {
michael@0 828 if (!(GetStateBits() & NS_FRAME_IS_NONDISPLAY) && !aTransformRoot) {
michael@0 829 if ((aFor == FOR_PAINTING && NS_SVGDisplayListPaintingEnabled()) ||
michael@0 830 (aFor == FOR_HIT_TESTING && NS_SVGDisplayListHitTestingEnabled())) {
michael@0 831 return nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(this);
michael@0 832 }
michael@0 833 }
michael@0 834 if (!mCanvasTM) {
michael@0 835 NS_ASSERTION(!aTransformRoot, "transform root will be ignored here");
michael@0 836 SVGSVGElement *content = static_cast<SVGSVGElement*>(mContent);
michael@0 837
michael@0 838 float devPxPerCSSPx =
michael@0 839 1.0f / PresContext()->AppUnitsToFloatCSSPixels(
michael@0 840 PresContext()->AppUnitsPerDevPixel());
michael@0 841
michael@0 842 gfxMatrix tm = content->PrependLocalTransformsTo(
michael@0 843 gfxMatrix().Scale(devPxPerCSSPx, devPxPerCSSPx));
michael@0 844 mCanvasTM = new gfxMatrix(tm);
michael@0 845 }
michael@0 846 return *mCanvasTM;
michael@0 847 }
michael@0 848
michael@0 849 //----------------------------------------------------------------------
michael@0 850 // Implementation helpers
michael@0 851
michael@0 852 bool
michael@0 853 nsSVGOuterSVGFrame::IsRootOfReplacedElementSubDoc(nsIFrame **aEmbeddingFrame)
michael@0 854 {
michael@0 855 if (!mContent->GetParent()) {
michael@0 856 // Our content is the document element
michael@0 857 nsCOMPtr<nsISupports> container = PresContext()->GetContainerWeak();
michael@0 858 nsCOMPtr<nsIDOMWindow> window = do_GetInterface(container);
michael@0 859 if (window) {
michael@0 860 nsCOMPtr<nsIDOMElement> frameElement;
michael@0 861 window->GetFrameElement(getter_AddRefs(frameElement));
michael@0 862 nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(frameElement);
michael@0 863 if (olc) {
michael@0 864 // Our document is inside an HTML 'object', 'embed' or 'applet' element
michael@0 865 if (aEmbeddingFrame) {
michael@0 866 nsCOMPtr<nsIContent> element = do_QueryInterface(frameElement);
michael@0 867 *aEmbeddingFrame = element->GetPrimaryFrame();
michael@0 868 NS_ASSERTION(*aEmbeddingFrame, "Yikes, no embedding frame!");
michael@0 869 }
michael@0 870 return true;
michael@0 871 }
michael@0 872 }
michael@0 873 }
michael@0 874 if (aEmbeddingFrame) {
michael@0 875 *aEmbeddingFrame = nullptr;
michael@0 876 }
michael@0 877 return false;
michael@0 878 }
michael@0 879
michael@0 880 bool
michael@0 881 nsSVGOuterSVGFrame::IsRootOfImage()
michael@0 882 {
michael@0 883 if (!mContent->GetParent()) {
michael@0 884 // Our content is the document element
michael@0 885 nsIDocument* doc = mContent->GetCurrentDoc();
michael@0 886 if (doc && doc->IsBeingUsedAsImage()) {
michael@0 887 // Our document is being used as an image
michael@0 888 return true;
michael@0 889 }
michael@0 890 }
michael@0 891
michael@0 892 return false;
michael@0 893 }
michael@0 894
michael@0 895 bool
michael@0 896 nsSVGOuterSVGFrame::VerticalScrollbarNotNeeded() const
michael@0 897 {
michael@0 898 nsSVGLength2 &height = static_cast<SVGSVGElement*>(mContent)->
michael@0 899 mLengthAttributes[SVGSVGElement::ATTR_HEIGHT];
michael@0 900 return height.IsPercentage() && height.GetBaseValInSpecifiedUnits() <= 100;
michael@0 901 }
michael@0 902
michael@0 903
michael@0 904 //----------------------------------------------------------------------
michael@0 905 // Implementation of nsSVGOuterSVGAnonChildFrame
michael@0 906
michael@0 907 nsIFrame*
michael@0 908 NS_NewSVGOuterSVGAnonChildFrame(nsIPresShell* aPresShell,
michael@0 909 nsStyleContext* aContext)
michael@0 910 {
michael@0 911 return new (aPresShell) nsSVGOuterSVGAnonChildFrame(aContext);
michael@0 912 }
michael@0 913
michael@0 914 NS_IMPL_FRAMEARENA_HELPERS(nsSVGOuterSVGAnonChildFrame)
michael@0 915
michael@0 916 #ifdef DEBUG
michael@0 917 void
michael@0 918 nsSVGOuterSVGAnonChildFrame::Init(nsIContent* aContent,
michael@0 919 nsIFrame* aParent,
michael@0 920 nsIFrame* aPrevInFlow)
michael@0 921 {
michael@0 922 NS_ABORT_IF_FALSE(aParent->GetType() == nsGkAtoms::svgOuterSVGFrame,
michael@0 923 "Unexpected parent");
michael@0 924 nsSVGOuterSVGAnonChildFrameBase::Init(aContent, aParent, aPrevInFlow);
michael@0 925 }
michael@0 926 #endif
michael@0 927
michael@0 928 nsIAtom *
michael@0 929 nsSVGOuterSVGAnonChildFrame::GetType() const
michael@0 930 {
michael@0 931 return nsGkAtoms::svgOuterSVGAnonChildFrame;
michael@0 932 }
michael@0 933
michael@0 934 bool
michael@0 935 nsSVGOuterSVGAnonChildFrame::HasChildrenOnlyTransform(gfx::Matrix *aTransform) const
michael@0 936 {
michael@0 937 // We must claim our nsSVGOuterSVGFrame's children-only transforms as our own
michael@0 938 // so that the children we are used to wrap are transformed properly.
michael@0 939
michael@0 940 SVGSVGElement *content = static_cast<SVGSVGElement*>(mContent);
michael@0 941
michael@0 942 bool hasTransform = content->HasChildrenOnlyTransform();
michael@0 943
michael@0 944 if (hasTransform && aTransform) {
michael@0 945 // Outer-<svg> doesn't use x/y, so we can pass eChildToUserSpace here.
michael@0 946 gfxMatrix identity;
michael@0 947 *aTransform = gfx::ToMatrix(
michael@0 948 content->PrependLocalTransformsTo(identity,
michael@0 949 nsSVGElement::eChildToUserSpace));
michael@0 950 }
michael@0 951
michael@0 952 return hasTransform;
michael@0 953 }

mercurial