1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/generic/nsCanvasFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,621 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* rendering object that goes directly inside the document's scrollbars */ 1.10 + 1.11 +#include "nsCanvasFrame.h" 1.12 +#include "nsContainerFrame.h" 1.13 +#include "nsCSSRendering.h" 1.14 +#include "nsPresContext.h" 1.15 +#include "nsStyleContext.h" 1.16 +#include "nsRenderingContext.h" 1.17 +#include "nsGkAtoms.h" 1.18 +#include "nsIPresShell.h" 1.19 +#include "nsDisplayList.h" 1.20 +#include "nsCSSFrameConstructor.h" 1.21 +#include "nsFrameManager.h" 1.22 +#include "gfxPlatform.h" 1.23 + 1.24 +// for focus 1.25 +#include "nsIScrollableFrame.h" 1.26 +#ifdef DEBUG_CANVAS_FOCUS 1.27 +#include "nsIDocShell.h" 1.28 +#endif 1.29 + 1.30 +//#define DEBUG_CANVAS_FOCUS 1.31 + 1.32 +using namespace mozilla; 1.33 +using namespace mozilla::layout; 1.34 +using namespace mozilla::gfx; 1.35 + 1.36 +nsIFrame* 1.37 +NS_NewCanvasFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) 1.38 +{ 1.39 + return new (aPresShell) nsCanvasFrame(aContext); 1.40 +} 1.41 + 1.42 +NS_IMPL_FRAMEARENA_HELPERS(nsCanvasFrame) 1.43 + 1.44 +NS_QUERYFRAME_HEAD(nsCanvasFrame) 1.45 + NS_QUERYFRAME_ENTRY(nsCanvasFrame) 1.46 +NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) 1.47 + 1.48 +void 1.49 +nsCanvasFrame::DestroyFrom(nsIFrame* aDestructRoot) 1.50 +{ 1.51 + nsIScrollableFrame* sf = 1.52 + PresContext()->GetPresShell()->GetRootScrollFrameAsScrollable(); 1.53 + if (sf) { 1.54 + sf->RemoveScrollPositionListener(this); 1.55 + } 1.56 + 1.57 + nsContainerFrame::DestroyFrom(aDestructRoot); 1.58 +} 1.59 + 1.60 +void 1.61 +nsCanvasFrame::ScrollPositionWillChange(nscoord aX, nscoord aY) 1.62 +{ 1.63 + if (mDoPaintFocus) { 1.64 + mDoPaintFocus = false; 1.65 + PresContext()->FrameManager()->GetRootFrame()->InvalidateFrameSubtree(); 1.66 + } 1.67 +} 1.68 + 1.69 +NS_IMETHODIMP 1.70 +nsCanvasFrame::SetHasFocus(bool aHasFocus) 1.71 +{ 1.72 + if (mDoPaintFocus != aHasFocus) { 1.73 + mDoPaintFocus = aHasFocus; 1.74 + PresContext()->FrameManager()->GetRootFrame()->InvalidateFrameSubtree(); 1.75 + 1.76 + if (!mAddedScrollPositionListener) { 1.77 + nsIScrollableFrame* sf = 1.78 + PresContext()->GetPresShell()->GetRootScrollFrameAsScrollable(); 1.79 + if (sf) { 1.80 + sf->AddScrollPositionListener(this); 1.81 + mAddedScrollPositionListener = true; 1.82 + } 1.83 + } 1.84 + } 1.85 + return NS_OK; 1.86 +} 1.87 + 1.88 +nsresult 1.89 +nsCanvasFrame::SetInitialChildList(ChildListID aListID, 1.90 + nsFrameList& aChildList) 1.91 +{ 1.92 + NS_ASSERTION(aListID != kPrincipalList || 1.93 + aChildList.IsEmpty() || aChildList.OnlyChild(), 1.94 + "Primary child list can have at most one frame in it"); 1.95 + return nsContainerFrame::SetInitialChildList(aListID, aChildList); 1.96 +} 1.97 + 1.98 +nsresult 1.99 +nsCanvasFrame::AppendFrames(ChildListID aListID, 1.100 + nsFrameList& aFrameList) 1.101 +{ 1.102 + NS_ASSERTION(aListID == kPrincipalList || 1.103 + aListID == kAbsoluteList, "unexpected child list ID"); 1.104 + NS_PRECONDITION(aListID != kAbsoluteList || 1.105 + mFrames.IsEmpty(), "already have a child frame"); 1.106 + if (aListID != kPrincipalList) { 1.107 + // We only support the Principal and Absolute child lists. 1.108 + return NS_ERROR_INVALID_ARG; 1.109 + } 1.110 + 1.111 + if (!mFrames.IsEmpty()) { 1.112 + // We only allow a single principal child frame. 1.113 + return NS_ERROR_INVALID_ARG; 1.114 + } 1.115 + 1.116 + // Insert the new frames 1.117 + NS_ASSERTION(aFrameList.FirstChild() == aFrameList.LastChild(), 1.118 + "Only one principal child frame allowed"); 1.119 +#ifdef DEBUG 1.120 + nsFrame::VerifyDirtyBitSet(aFrameList); 1.121 +#endif 1.122 + mFrames.AppendFrames(nullptr, aFrameList); 1.123 + 1.124 + PresContext()->PresShell()-> 1.125 + FrameNeedsReflow(this, nsIPresShell::eTreeChange, 1.126 + NS_FRAME_HAS_DIRTY_CHILDREN); 1.127 + 1.128 + return NS_OK; 1.129 +} 1.130 + 1.131 +nsresult 1.132 +nsCanvasFrame::InsertFrames(ChildListID aListID, 1.133 + nsIFrame* aPrevFrame, 1.134 + nsFrameList& aFrameList) 1.135 +{ 1.136 + // Because we only support a single child frame inserting is the same 1.137 + // as appending 1.138 + NS_PRECONDITION(!aPrevFrame, "unexpected previous sibling frame"); 1.139 + if (aPrevFrame) 1.140 + return NS_ERROR_UNEXPECTED; 1.141 + 1.142 + return AppendFrames(aListID, aFrameList); 1.143 +} 1.144 + 1.145 +nsresult 1.146 +nsCanvasFrame::RemoveFrame(ChildListID aListID, 1.147 + nsIFrame* aOldFrame) 1.148 +{ 1.149 + NS_ASSERTION(aListID == kPrincipalList || 1.150 + aListID == kAbsoluteList, "unexpected child list ID"); 1.151 + if (aListID != kPrincipalList && aListID != kAbsoluteList) { 1.152 + // We only support the Principal and Absolute child lists. 1.153 + return NS_ERROR_INVALID_ARG; 1.154 + } 1.155 + 1.156 + if (aOldFrame != mFrames.FirstChild()) 1.157 + return NS_ERROR_FAILURE; 1.158 + 1.159 + // Remove the frame and destroy it 1.160 + mFrames.DestroyFrame(aOldFrame); 1.161 + 1.162 + PresContext()->PresShell()-> 1.163 + FrameNeedsReflow(this, nsIPresShell::eTreeChange, 1.164 + NS_FRAME_HAS_DIRTY_CHILDREN); 1.165 + return NS_OK; 1.166 +} 1.167 + 1.168 +nsRect nsCanvasFrame::CanvasArea() const 1.169 +{ 1.170 + // Not clear which overflow rect we want here, but it probably doesn't 1.171 + // matter. 1.172 + nsRect result(GetVisualOverflowRect()); 1.173 + 1.174 + nsIScrollableFrame *scrollableFrame = do_QueryFrame(GetParent()); 1.175 + if (scrollableFrame) { 1.176 + nsRect portRect = scrollableFrame->GetScrollPortRect(); 1.177 + result.UnionRect(result, nsRect(nsPoint(0, 0), portRect.Size())); 1.178 + } 1.179 + return result; 1.180 +} 1.181 + 1.182 +void 1.183 +nsDisplayCanvasBackgroundColor::Paint(nsDisplayListBuilder* aBuilder, 1.184 + nsRenderingContext* aCtx) 1.185 +{ 1.186 + nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame); 1.187 + nsPoint offset = ToReferenceFrame(); 1.188 + nsRect bgClipRect = frame->CanvasArea() + offset; 1.189 + if (NS_GET_A(mColor) > 0) { 1.190 + aCtx->SetColor(mColor); 1.191 + aCtx->FillRect(bgClipRect); 1.192 + } 1.193 +} 1.194 + 1.195 +static void BlitSurface(gfxContext* aDest, const gfxRect& aRect, gfxASurface* aSource) 1.196 +{ 1.197 + aDest->Translate(gfxPoint(aRect.x, aRect.y)); 1.198 + aDest->SetSource(aSource); 1.199 + aDest->NewPath(); 1.200 + aDest->Rectangle(gfxRect(0, 0, aRect.width, aRect.height)); 1.201 + aDest->Fill(); 1.202 + aDest->Translate(-gfxPoint(aRect.x, aRect.y)); 1.203 +} 1.204 + 1.205 +static void BlitSurface(DrawTarget* aDest, const gfxRect& aRect, DrawTarget* aSource) 1.206 +{ 1.207 + RefPtr<SourceSurface> source = aSource->Snapshot(); 1.208 + aDest->DrawSurface(source, 1.209 + Rect(aRect.x, aRect.y, aRect.width, aRect.height), 1.210 + Rect(0, 0, aRect.width, aRect.height)); 1.211 +} 1.212 + 1.213 +void 1.214 +nsDisplayCanvasBackgroundImage::Paint(nsDisplayListBuilder* aBuilder, 1.215 + nsRenderingContext* aCtx) 1.216 +{ 1.217 + nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame); 1.218 + nsPoint offset = ToReferenceFrame(); 1.219 + nsRect bgClipRect = frame->CanvasArea() + offset; 1.220 + 1.221 + nsRefPtr<nsRenderingContext> context; 1.222 + nsRefPtr<gfxContext> dest = aCtx->ThebesContext(); 1.223 + nsRefPtr<gfxASurface> surf; 1.224 + RefPtr<DrawTarget> dt; 1.225 + nsRefPtr<gfxContext> ctx; 1.226 + gfxRect destRect; 1.227 +#ifndef MOZ_GFX_OPTIMIZE_MOBILE 1.228 + if (IsSingleFixedPositionImage(aBuilder, bgClipRect, &destRect) && 1.229 + aBuilder->IsPaintingToWindow() && !aBuilder->IsCompositingCheap() && 1.230 + !dest->CurrentMatrix().HasNonIntegerTranslation()) { 1.231 + // Snap image rectangle to nearest pixel boundaries. This is the right way 1.232 + // to snap for this context, because we checked HasNonIntegerTranslation above. 1.233 + destRect.Round(); 1.234 + if (dest->IsCairo()) { 1.235 + surf = static_cast<gfxASurface*>(Frame()->Properties().Get(nsIFrame::CachedBackgroundImage())); 1.236 + nsRefPtr<gfxASurface> destSurf = dest->CurrentSurface(); 1.237 + if (surf && surf->GetType() == destSurf->GetType()) { 1.238 + BlitSurface(dest, destRect, surf); 1.239 + return; 1.240 + } 1.241 + surf = destSurf->CreateSimilarSurface( 1.242 + gfxContentType::COLOR_ALPHA, 1.243 + gfxIntSize(ceil(destRect.width), ceil(destRect.height))); 1.244 + } else { 1.245 + dt = static_cast<DrawTarget*>(Frame()->Properties().Get(nsIFrame::CachedBackgroundImageDT())); 1.246 + DrawTarget* destDT = dest->GetDrawTarget(); 1.247 + if (dt) { 1.248 + BlitSurface(destDT, destRect, dt); 1.249 + return; 1.250 + } 1.251 + dt = destDT->CreateSimilarDrawTarget(IntSize(ceil(destRect.width), ceil(destRect.height)), SurfaceFormat::B8G8R8A8); 1.252 + } 1.253 + if (surf || dt) { 1.254 + if (surf) { 1.255 + ctx = new gfxContext(surf); 1.256 + } else { 1.257 + ctx = new gfxContext(dt); 1.258 + } 1.259 + ctx->Translate(-gfxPoint(destRect.x, destRect.y)); 1.260 + context = new nsRenderingContext(); 1.261 + context->Init(aCtx->DeviceContext(), ctx); 1.262 + } 1.263 + } 1.264 +#endif 1.265 + 1.266 + PaintInternal(aBuilder, 1.267 + (surf || dt) ? context.get() : aCtx, 1.268 + (surf || dt) ? bgClipRect: mVisibleRect, 1.269 + &bgClipRect); 1.270 + 1.271 + if (surf) { 1.272 + BlitSurface(dest, destRect, surf); 1.273 + frame->Properties().Set(nsIFrame::CachedBackgroundImage(), 1.274 + surf.forget().take()); 1.275 + } 1.276 + if (dt) { 1.277 + BlitSurface(dest->GetDrawTarget(), destRect, dt); 1.278 + frame->Properties().Set(nsIFrame::CachedBackgroundImageDT(), dt.forget().drop()); 1.279 + } 1.280 +} 1.281 + 1.282 +void 1.283 +nsDisplayCanvasThemedBackground::Paint(nsDisplayListBuilder* aBuilder, 1.284 + nsRenderingContext* aCtx) 1.285 +{ 1.286 + nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame); 1.287 + nsPoint offset = ToReferenceFrame(); 1.288 + nsRect bgClipRect = frame->CanvasArea() + offset; 1.289 + 1.290 + PaintInternal(aBuilder, aCtx, mVisibleRect, &bgClipRect); 1.291 +} 1.292 + 1.293 +/** 1.294 + * A display item to paint the focus ring for the document. 1.295 + * 1.296 + * The only reason this can't use nsDisplayGeneric is overriding GetBounds. 1.297 + */ 1.298 +class nsDisplayCanvasFocus : public nsDisplayItem { 1.299 +public: 1.300 + nsDisplayCanvasFocus(nsDisplayListBuilder* aBuilder, nsCanvasFrame *aFrame) 1.301 + : nsDisplayItem(aBuilder, aFrame) 1.302 + { 1.303 + MOZ_COUNT_CTOR(nsDisplayCanvasFocus); 1.304 + } 1.305 + virtual ~nsDisplayCanvasFocus() { 1.306 + MOZ_COUNT_DTOR(nsDisplayCanvasFocus); 1.307 + } 1.308 + 1.309 + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, 1.310 + bool* aSnap) MOZ_OVERRIDE 1.311 + { 1.312 + *aSnap = false; 1.313 + // This is an overestimate, but that's not a problem. 1.314 + nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame); 1.315 + return frame->CanvasArea() + ToReferenceFrame(); 1.316 + } 1.317 + 1.318 + virtual void Paint(nsDisplayListBuilder* aBuilder, 1.319 + nsRenderingContext* aCtx) MOZ_OVERRIDE 1.320 + { 1.321 + nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame); 1.322 + frame->PaintFocus(*aCtx, ToReferenceFrame()); 1.323 + } 1.324 + 1.325 + NS_DISPLAY_DECL_NAME("CanvasFocus", TYPE_CANVAS_FOCUS) 1.326 +}; 1.327 + 1.328 +void 1.329 +nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, 1.330 + const nsRect& aDirtyRect, 1.331 + const nsDisplayListSet& aLists) 1.332 +{ 1.333 + if (GetPrevInFlow()) { 1.334 + DisplayOverflowContainers(aBuilder, aDirtyRect, aLists); 1.335 + } 1.336 + 1.337 + // Force a background to be shown. We may have a background propagated to us, 1.338 + // in which case StyleBackground wouldn't have the right background 1.339 + // and the code in nsFrame::DisplayBorderBackgroundOutline might not give us 1.340 + // a background. 1.341 + // We don't have any border or outline, and our background draws over 1.342 + // the overflow area, so just add nsDisplayCanvasBackground instead of 1.343 + // calling DisplayBorderBackgroundOutline. 1.344 + if (IsVisibleForPainting(aBuilder)) { 1.345 + nsStyleContext* bgSC; 1.346 + const nsStyleBackground* bg = nullptr; 1.347 + bool isThemed = IsThemed(); 1.348 + if (!isThemed && nsCSSRendering::FindBackground(this, &bgSC)) { 1.349 + bg = bgSC->StyleBackground(); 1.350 + } 1.351 + aLists.BorderBackground()->AppendNewToTop( 1.352 + new (aBuilder) nsDisplayCanvasBackgroundColor(aBuilder, this)); 1.353 + 1.354 + if (isThemed) { 1.355 + aLists.BorderBackground()->AppendNewToTop( 1.356 + new (aBuilder) nsDisplayCanvasThemedBackground(aBuilder, this)); 1.357 + return; 1.358 + } 1.359 + 1.360 + if (!bg) { 1.361 + return; 1.362 + } 1.363 + 1.364 + // Create separate items for each background layer. 1.365 + NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) { 1.366 + if (bg->mLayers[i].mImage.IsEmpty()) { 1.367 + continue; 1.368 + } 1.369 + aLists.BorderBackground()->AppendNewToTop( 1.370 + new (aBuilder) nsDisplayCanvasBackgroundImage(aBuilder, this, i, bg)); 1.371 + } 1.372 + } 1.373 + 1.374 + nsIFrame* kid; 1.375 + for (kid = GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) { 1.376 + // Put our child into its own pseudo-stack. 1.377 + BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists); 1.378 + } 1.379 + 1.380 +#ifdef DEBUG_CANVAS_FOCUS 1.381 + nsCOMPtr<nsIContent> focusContent; 1.382 + aPresContext->EventStateManager()-> 1.383 + GetFocusedContent(getter_AddRefs(focusContent)); 1.384 + 1.385 + bool hasFocus = false; 1.386 + nsCOMPtr<nsISupports> container; 1.387 + aPresContext->GetContainer(getter_AddRefs(container)); 1.388 + nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container)); 1.389 + if (docShell) { 1.390 + docShell->GetHasFocus(&hasFocus); 1.391 + printf("%p - nsCanvasFrame::Paint R:%d,%d,%d,%d DR: %d,%d,%d,%d\n", this, 1.392 + mRect.x, mRect.y, mRect.width, mRect.height, 1.393 + aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height); 1.394 + } 1.395 + printf("%p - Focus: %s c: %p DoPaint:%s\n", docShell.get(), hasFocus?"Y":"N", 1.396 + focusContent.get(), mDoPaintFocus?"Y":"N"); 1.397 +#endif 1.398 + 1.399 + if (!mDoPaintFocus) 1.400 + return; 1.401 + // Only paint the focus if we're visible 1.402 + if (!StyleVisibility()->IsVisible()) 1.403 + return; 1.404 + 1.405 + aLists.Outlines()->AppendNewToTop(new (aBuilder) 1.406 + nsDisplayCanvasFocus(aBuilder, this)); 1.407 +} 1.408 + 1.409 +void 1.410 +nsCanvasFrame::PaintFocus(nsRenderingContext& aRenderingContext, nsPoint aPt) 1.411 +{ 1.412 + nsRect focusRect(aPt, GetSize()); 1.413 + 1.414 + nsIScrollableFrame *scrollableFrame = do_QueryFrame(GetParent()); 1.415 + if (scrollableFrame) { 1.416 + nsRect portRect = scrollableFrame->GetScrollPortRect(); 1.417 + focusRect.width = portRect.width; 1.418 + focusRect.height = portRect.height; 1.419 + focusRect.MoveBy(scrollableFrame->GetScrollPosition()); 1.420 + } 1.421 + 1.422 + // XXX use the root frame foreground color, but should we find BODY frame 1.423 + // for HTML documents? 1.424 + nsIFrame* root = mFrames.FirstChild(); 1.425 + const nsStyleColor* color = root ? root->StyleColor() : StyleColor(); 1.426 + if (!color) { 1.427 + NS_ERROR("current color cannot be found"); 1.428 + return; 1.429 + } 1.430 + 1.431 + nsCSSRendering::PaintFocus(PresContext(), aRenderingContext, 1.432 + focusRect, color->mColor); 1.433 +} 1.434 + 1.435 +/* virtual */ nscoord 1.436 +nsCanvasFrame::GetMinWidth(nsRenderingContext *aRenderingContext) 1.437 +{ 1.438 + nscoord result; 1.439 + DISPLAY_MIN_WIDTH(this, result); 1.440 + if (mFrames.IsEmpty()) 1.441 + result = 0; 1.442 + else 1.443 + result = mFrames.FirstChild()->GetMinWidth(aRenderingContext); 1.444 + return result; 1.445 +} 1.446 + 1.447 +/* virtual */ nscoord 1.448 +nsCanvasFrame::GetPrefWidth(nsRenderingContext *aRenderingContext) 1.449 +{ 1.450 + nscoord result; 1.451 + DISPLAY_PREF_WIDTH(this, result); 1.452 + if (mFrames.IsEmpty()) 1.453 + result = 0; 1.454 + else 1.455 + result = mFrames.FirstChild()->GetPrefWidth(aRenderingContext); 1.456 + return result; 1.457 +} 1.458 + 1.459 +nsresult 1.460 +nsCanvasFrame::Reflow(nsPresContext* aPresContext, 1.461 + nsHTMLReflowMetrics& aDesiredSize, 1.462 + const nsHTMLReflowState& aReflowState, 1.463 + nsReflowStatus& aStatus) 1.464 +{ 1.465 + DO_GLOBAL_REFLOW_COUNT("nsCanvasFrame"); 1.466 + DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); 1.467 + NS_FRAME_TRACE_REFLOW_IN("nsCanvasFrame::Reflow"); 1.468 + 1.469 + // Initialize OUT parameter 1.470 + aStatus = NS_FRAME_COMPLETE; 1.471 + 1.472 + nsCanvasFrame* prevCanvasFrame = static_cast<nsCanvasFrame*> 1.473 + (GetPrevInFlow()); 1.474 + if (prevCanvasFrame) { 1.475 + AutoFrameListPtr overflow(aPresContext, 1.476 + prevCanvasFrame->StealOverflowFrames()); 1.477 + if (overflow) { 1.478 + NS_ASSERTION(overflow->OnlyChild(), 1.479 + "must have doc root as canvas frame's only child"); 1.480 + nsContainerFrame::ReparentFrameViewList(*overflow, prevCanvasFrame, this); 1.481 + // Prepend overflow to the our child list. There may already be 1.482 + // children placeholders for fixed-pos elements, which don't get 1.483 + // reflowed but must not be lost until the canvas frame is destroyed. 1.484 + mFrames.InsertFrames(this, nullptr, *overflow); 1.485 + } 1.486 + } 1.487 + 1.488 + // Set our size up front, since some parts of reflow depend on it 1.489 + // being already set. Note that the computed height may be 1.490 + // unconstrained; that's ok. Consumers should watch out for that. 1.491 + SetSize(nsSize(aReflowState.ComputedWidth(), aReflowState.ComputedHeight())); 1.492 + 1.493 + // Reflow our one and only normal child frame. It's either the root 1.494 + // element's frame or a placeholder for that frame, if the root element 1.495 + // is abs-pos or fixed-pos. We may have additional children which 1.496 + // are placeholders for continuations of fixed-pos content, but those 1.497 + // don't need to be reflowed. The normal child is always comes before 1.498 + // the fixed-pos placeholders, because we insert it at the start 1.499 + // of the child list, above. 1.500 + nsHTMLReflowMetrics kidDesiredSize(aReflowState); 1.501 + if (mFrames.IsEmpty()) { 1.502 + // We have no child frame, so return an empty size 1.503 + aDesiredSize.Width() = aDesiredSize.Height() = 0; 1.504 + } else { 1.505 + nsIFrame* kidFrame = mFrames.FirstChild(); 1.506 + bool kidDirty = (kidFrame->GetStateBits() & NS_FRAME_IS_DIRTY) != 0; 1.507 + 1.508 + nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, 1.509 + nsSize(aReflowState.AvailableWidth(), 1.510 + aReflowState.AvailableHeight())); 1.511 + 1.512 + if (aReflowState.mFlags.mVResize && 1.513 + (kidFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT)) { 1.514 + // Tell our kid it's being vertically resized too. Bit of a 1.515 + // hack for framesets. 1.516 + kidReflowState.mFlags.mVResize = true; 1.517 + } 1.518 + 1.519 + nsPoint kidPt(kidReflowState.ComputedPhysicalMargin().left, 1.520 + kidReflowState.ComputedPhysicalMargin().top); 1.521 + 1.522 + kidReflowState.ApplyRelativePositioning(&kidPt); 1.523 + 1.524 + // Reflow the frame 1.525 + ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState, 1.526 + kidPt.x, kidPt.y, 0, aStatus); 1.527 + 1.528 + // Complete the reflow and position and size the child frame 1.529 + FinishReflowChild(kidFrame, aPresContext, kidDesiredSize, &kidReflowState, 1.530 + kidPt.x, kidPt.y, 0); 1.531 + 1.532 + if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) { 1.533 + nsIFrame* nextFrame = kidFrame->GetNextInFlow(); 1.534 + NS_ASSERTION(nextFrame || aStatus & NS_FRAME_REFLOW_NEXTINFLOW, 1.535 + "If it's incomplete and has no nif yet, it must flag a nif reflow."); 1.536 + if (!nextFrame) { 1.537 + nextFrame = aPresContext->PresShell()->FrameConstructor()-> 1.538 + CreateContinuingFrame(aPresContext, kidFrame, this); 1.539 + SetOverflowFrames(nsFrameList(nextFrame, nextFrame)); 1.540 + // Root overflow containers will be normal children of 1.541 + // the canvas frame, but that's ok because there 1.542 + // aren't any other frames we need to isolate them from 1.543 + // during reflow. 1.544 + } 1.545 + if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) { 1.546 + nextFrame->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER); 1.547 + } 1.548 + } 1.549 + 1.550 + // If the child frame was just inserted, then we're responsible for making sure 1.551 + // it repaints 1.552 + if (kidDirty) { 1.553 + // But we have a new child, which will affect our background, so 1.554 + // invalidate our whole rect. 1.555 + // Note: Even though we request to be sized to our child's size, our 1.556 + // scroll frame ensures that we are always the size of the viewport. 1.557 + // Also note: GetPosition() on a CanvasFrame is always going to return 1.558 + // (0, 0). We only want to invalidate GetRect() since Get*OverflowRect() 1.559 + // could also include overflow to our top and left (out of the viewport) 1.560 + // which doesn't need to be painted. 1.561 + nsIFrame* viewport = PresContext()->GetPresShell()->GetRootFrame(); 1.562 + viewport->InvalidateFrame(); 1.563 + } 1.564 + 1.565 + // Return our desired size. Normally it's what we're told, but 1.566 + // sometimes we can be given an unconstrained height (when a window 1.567 + // is sizing-to-content), and we should compute our desired height. 1.568 + aDesiredSize.Width() = aReflowState.ComputedWidth(); 1.569 + if (aReflowState.ComputedHeight() == NS_UNCONSTRAINEDSIZE) { 1.570 + aDesiredSize.Height() = kidFrame->GetRect().height + 1.571 + kidReflowState.ComputedPhysicalMargin().TopBottom(); 1.572 + } else { 1.573 + aDesiredSize.Height() = aReflowState.ComputedHeight(); 1.574 + } 1.575 + 1.576 + aDesiredSize.SetOverflowAreasToDesiredBounds(); 1.577 + aDesiredSize.mOverflowAreas.UnionWith( 1.578 + kidDesiredSize.mOverflowAreas + kidPt); 1.579 + } 1.580 + 1.581 + if (prevCanvasFrame) { 1.582 + ReflowOverflowContainerChildren(aPresContext, aReflowState, 1.583 + aDesiredSize.mOverflowAreas, 0, 1.584 + aStatus); 1.585 + } 1.586 + 1.587 + FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus); 1.588 + 1.589 + NS_FRAME_TRACE_REFLOW_OUT("nsCanvasFrame::Reflow", aStatus); 1.590 + NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); 1.591 + return NS_OK; 1.592 +} 1.593 + 1.594 +nsIAtom* 1.595 +nsCanvasFrame::GetType() const 1.596 +{ 1.597 + return nsGkAtoms::canvasFrame; 1.598 +} 1.599 + 1.600 +nsresult 1.601 +nsCanvasFrame::GetContentForEvent(WidgetEvent* aEvent, 1.602 + nsIContent** aContent) 1.603 +{ 1.604 + NS_ENSURE_ARG_POINTER(aContent); 1.605 + nsresult rv = nsFrame::GetContentForEvent(aEvent, 1.606 + aContent); 1.607 + if (NS_FAILED(rv) || !*aContent) { 1.608 + nsIFrame* kid = mFrames.FirstChild(); 1.609 + if (kid) { 1.610 + rv = kid->GetContentForEvent(aEvent, 1.611 + aContent); 1.612 + } 1.613 + } 1.614 + 1.615 + return rv; 1.616 +} 1.617 + 1.618 +#ifdef DEBUG_FRAME_DUMP 1.619 +nsresult 1.620 +nsCanvasFrame::GetFrameName(nsAString& aResult) const 1.621 +{ 1.622 + return MakeFrameName(NS_LITERAL_STRING("Canvas"), aResult); 1.623 +} 1.624 +#endif