layout/generic/nsCanvasFrame.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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 /* rendering object that goes directly inside the document's scrollbars */
michael@0 7
michael@0 8 #include "nsCanvasFrame.h"
michael@0 9 #include "nsContainerFrame.h"
michael@0 10 #include "nsCSSRendering.h"
michael@0 11 #include "nsPresContext.h"
michael@0 12 #include "nsStyleContext.h"
michael@0 13 #include "nsRenderingContext.h"
michael@0 14 #include "nsGkAtoms.h"
michael@0 15 #include "nsIPresShell.h"
michael@0 16 #include "nsDisplayList.h"
michael@0 17 #include "nsCSSFrameConstructor.h"
michael@0 18 #include "nsFrameManager.h"
michael@0 19 #include "gfxPlatform.h"
michael@0 20
michael@0 21 // for focus
michael@0 22 #include "nsIScrollableFrame.h"
michael@0 23 #ifdef DEBUG_CANVAS_FOCUS
michael@0 24 #include "nsIDocShell.h"
michael@0 25 #endif
michael@0 26
michael@0 27 //#define DEBUG_CANVAS_FOCUS
michael@0 28
michael@0 29 using namespace mozilla;
michael@0 30 using namespace mozilla::layout;
michael@0 31 using namespace mozilla::gfx;
michael@0 32
michael@0 33 nsIFrame*
michael@0 34 NS_NewCanvasFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
michael@0 35 {
michael@0 36 return new (aPresShell) nsCanvasFrame(aContext);
michael@0 37 }
michael@0 38
michael@0 39 NS_IMPL_FRAMEARENA_HELPERS(nsCanvasFrame)
michael@0 40
michael@0 41 NS_QUERYFRAME_HEAD(nsCanvasFrame)
michael@0 42 NS_QUERYFRAME_ENTRY(nsCanvasFrame)
michael@0 43 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
michael@0 44
michael@0 45 void
michael@0 46 nsCanvasFrame::DestroyFrom(nsIFrame* aDestructRoot)
michael@0 47 {
michael@0 48 nsIScrollableFrame* sf =
michael@0 49 PresContext()->GetPresShell()->GetRootScrollFrameAsScrollable();
michael@0 50 if (sf) {
michael@0 51 sf->RemoveScrollPositionListener(this);
michael@0 52 }
michael@0 53
michael@0 54 nsContainerFrame::DestroyFrom(aDestructRoot);
michael@0 55 }
michael@0 56
michael@0 57 void
michael@0 58 nsCanvasFrame::ScrollPositionWillChange(nscoord aX, nscoord aY)
michael@0 59 {
michael@0 60 if (mDoPaintFocus) {
michael@0 61 mDoPaintFocus = false;
michael@0 62 PresContext()->FrameManager()->GetRootFrame()->InvalidateFrameSubtree();
michael@0 63 }
michael@0 64 }
michael@0 65
michael@0 66 NS_IMETHODIMP
michael@0 67 nsCanvasFrame::SetHasFocus(bool aHasFocus)
michael@0 68 {
michael@0 69 if (mDoPaintFocus != aHasFocus) {
michael@0 70 mDoPaintFocus = aHasFocus;
michael@0 71 PresContext()->FrameManager()->GetRootFrame()->InvalidateFrameSubtree();
michael@0 72
michael@0 73 if (!mAddedScrollPositionListener) {
michael@0 74 nsIScrollableFrame* sf =
michael@0 75 PresContext()->GetPresShell()->GetRootScrollFrameAsScrollable();
michael@0 76 if (sf) {
michael@0 77 sf->AddScrollPositionListener(this);
michael@0 78 mAddedScrollPositionListener = true;
michael@0 79 }
michael@0 80 }
michael@0 81 }
michael@0 82 return NS_OK;
michael@0 83 }
michael@0 84
michael@0 85 nsresult
michael@0 86 nsCanvasFrame::SetInitialChildList(ChildListID aListID,
michael@0 87 nsFrameList& aChildList)
michael@0 88 {
michael@0 89 NS_ASSERTION(aListID != kPrincipalList ||
michael@0 90 aChildList.IsEmpty() || aChildList.OnlyChild(),
michael@0 91 "Primary child list can have at most one frame in it");
michael@0 92 return nsContainerFrame::SetInitialChildList(aListID, aChildList);
michael@0 93 }
michael@0 94
michael@0 95 nsresult
michael@0 96 nsCanvasFrame::AppendFrames(ChildListID aListID,
michael@0 97 nsFrameList& aFrameList)
michael@0 98 {
michael@0 99 NS_ASSERTION(aListID == kPrincipalList ||
michael@0 100 aListID == kAbsoluteList, "unexpected child list ID");
michael@0 101 NS_PRECONDITION(aListID != kAbsoluteList ||
michael@0 102 mFrames.IsEmpty(), "already have a child frame");
michael@0 103 if (aListID != kPrincipalList) {
michael@0 104 // We only support the Principal and Absolute child lists.
michael@0 105 return NS_ERROR_INVALID_ARG;
michael@0 106 }
michael@0 107
michael@0 108 if (!mFrames.IsEmpty()) {
michael@0 109 // We only allow a single principal child frame.
michael@0 110 return NS_ERROR_INVALID_ARG;
michael@0 111 }
michael@0 112
michael@0 113 // Insert the new frames
michael@0 114 NS_ASSERTION(aFrameList.FirstChild() == aFrameList.LastChild(),
michael@0 115 "Only one principal child frame allowed");
michael@0 116 #ifdef DEBUG
michael@0 117 nsFrame::VerifyDirtyBitSet(aFrameList);
michael@0 118 #endif
michael@0 119 mFrames.AppendFrames(nullptr, aFrameList);
michael@0 120
michael@0 121 PresContext()->PresShell()->
michael@0 122 FrameNeedsReflow(this, nsIPresShell::eTreeChange,
michael@0 123 NS_FRAME_HAS_DIRTY_CHILDREN);
michael@0 124
michael@0 125 return NS_OK;
michael@0 126 }
michael@0 127
michael@0 128 nsresult
michael@0 129 nsCanvasFrame::InsertFrames(ChildListID aListID,
michael@0 130 nsIFrame* aPrevFrame,
michael@0 131 nsFrameList& aFrameList)
michael@0 132 {
michael@0 133 // Because we only support a single child frame inserting is the same
michael@0 134 // as appending
michael@0 135 NS_PRECONDITION(!aPrevFrame, "unexpected previous sibling frame");
michael@0 136 if (aPrevFrame)
michael@0 137 return NS_ERROR_UNEXPECTED;
michael@0 138
michael@0 139 return AppendFrames(aListID, aFrameList);
michael@0 140 }
michael@0 141
michael@0 142 nsresult
michael@0 143 nsCanvasFrame::RemoveFrame(ChildListID aListID,
michael@0 144 nsIFrame* aOldFrame)
michael@0 145 {
michael@0 146 NS_ASSERTION(aListID == kPrincipalList ||
michael@0 147 aListID == kAbsoluteList, "unexpected child list ID");
michael@0 148 if (aListID != kPrincipalList && aListID != kAbsoluteList) {
michael@0 149 // We only support the Principal and Absolute child lists.
michael@0 150 return NS_ERROR_INVALID_ARG;
michael@0 151 }
michael@0 152
michael@0 153 if (aOldFrame != mFrames.FirstChild())
michael@0 154 return NS_ERROR_FAILURE;
michael@0 155
michael@0 156 // Remove the frame and destroy it
michael@0 157 mFrames.DestroyFrame(aOldFrame);
michael@0 158
michael@0 159 PresContext()->PresShell()->
michael@0 160 FrameNeedsReflow(this, nsIPresShell::eTreeChange,
michael@0 161 NS_FRAME_HAS_DIRTY_CHILDREN);
michael@0 162 return NS_OK;
michael@0 163 }
michael@0 164
michael@0 165 nsRect nsCanvasFrame::CanvasArea() const
michael@0 166 {
michael@0 167 // Not clear which overflow rect we want here, but it probably doesn't
michael@0 168 // matter.
michael@0 169 nsRect result(GetVisualOverflowRect());
michael@0 170
michael@0 171 nsIScrollableFrame *scrollableFrame = do_QueryFrame(GetParent());
michael@0 172 if (scrollableFrame) {
michael@0 173 nsRect portRect = scrollableFrame->GetScrollPortRect();
michael@0 174 result.UnionRect(result, nsRect(nsPoint(0, 0), portRect.Size()));
michael@0 175 }
michael@0 176 return result;
michael@0 177 }
michael@0 178
michael@0 179 void
michael@0 180 nsDisplayCanvasBackgroundColor::Paint(nsDisplayListBuilder* aBuilder,
michael@0 181 nsRenderingContext* aCtx)
michael@0 182 {
michael@0 183 nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
michael@0 184 nsPoint offset = ToReferenceFrame();
michael@0 185 nsRect bgClipRect = frame->CanvasArea() + offset;
michael@0 186 if (NS_GET_A(mColor) > 0) {
michael@0 187 aCtx->SetColor(mColor);
michael@0 188 aCtx->FillRect(bgClipRect);
michael@0 189 }
michael@0 190 }
michael@0 191
michael@0 192 static void BlitSurface(gfxContext* aDest, const gfxRect& aRect, gfxASurface* aSource)
michael@0 193 {
michael@0 194 aDest->Translate(gfxPoint(aRect.x, aRect.y));
michael@0 195 aDest->SetSource(aSource);
michael@0 196 aDest->NewPath();
michael@0 197 aDest->Rectangle(gfxRect(0, 0, aRect.width, aRect.height));
michael@0 198 aDest->Fill();
michael@0 199 aDest->Translate(-gfxPoint(aRect.x, aRect.y));
michael@0 200 }
michael@0 201
michael@0 202 static void BlitSurface(DrawTarget* aDest, const gfxRect& aRect, DrawTarget* aSource)
michael@0 203 {
michael@0 204 RefPtr<SourceSurface> source = aSource->Snapshot();
michael@0 205 aDest->DrawSurface(source,
michael@0 206 Rect(aRect.x, aRect.y, aRect.width, aRect.height),
michael@0 207 Rect(0, 0, aRect.width, aRect.height));
michael@0 208 }
michael@0 209
michael@0 210 void
michael@0 211 nsDisplayCanvasBackgroundImage::Paint(nsDisplayListBuilder* aBuilder,
michael@0 212 nsRenderingContext* aCtx)
michael@0 213 {
michael@0 214 nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
michael@0 215 nsPoint offset = ToReferenceFrame();
michael@0 216 nsRect bgClipRect = frame->CanvasArea() + offset;
michael@0 217
michael@0 218 nsRefPtr<nsRenderingContext> context;
michael@0 219 nsRefPtr<gfxContext> dest = aCtx->ThebesContext();
michael@0 220 nsRefPtr<gfxASurface> surf;
michael@0 221 RefPtr<DrawTarget> dt;
michael@0 222 nsRefPtr<gfxContext> ctx;
michael@0 223 gfxRect destRect;
michael@0 224 #ifndef MOZ_GFX_OPTIMIZE_MOBILE
michael@0 225 if (IsSingleFixedPositionImage(aBuilder, bgClipRect, &destRect) &&
michael@0 226 aBuilder->IsPaintingToWindow() && !aBuilder->IsCompositingCheap() &&
michael@0 227 !dest->CurrentMatrix().HasNonIntegerTranslation()) {
michael@0 228 // Snap image rectangle to nearest pixel boundaries. This is the right way
michael@0 229 // to snap for this context, because we checked HasNonIntegerTranslation above.
michael@0 230 destRect.Round();
michael@0 231 if (dest->IsCairo()) {
michael@0 232 surf = static_cast<gfxASurface*>(Frame()->Properties().Get(nsIFrame::CachedBackgroundImage()));
michael@0 233 nsRefPtr<gfxASurface> destSurf = dest->CurrentSurface();
michael@0 234 if (surf && surf->GetType() == destSurf->GetType()) {
michael@0 235 BlitSurface(dest, destRect, surf);
michael@0 236 return;
michael@0 237 }
michael@0 238 surf = destSurf->CreateSimilarSurface(
michael@0 239 gfxContentType::COLOR_ALPHA,
michael@0 240 gfxIntSize(ceil(destRect.width), ceil(destRect.height)));
michael@0 241 } else {
michael@0 242 dt = static_cast<DrawTarget*>(Frame()->Properties().Get(nsIFrame::CachedBackgroundImageDT()));
michael@0 243 DrawTarget* destDT = dest->GetDrawTarget();
michael@0 244 if (dt) {
michael@0 245 BlitSurface(destDT, destRect, dt);
michael@0 246 return;
michael@0 247 }
michael@0 248 dt = destDT->CreateSimilarDrawTarget(IntSize(ceil(destRect.width), ceil(destRect.height)), SurfaceFormat::B8G8R8A8);
michael@0 249 }
michael@0 250 if (surf || dt) {
michael@0 251 if (surf) {
michael@0 252 ctx = new gfxContext(surf);
michael@0 253 } else {
michael@0 254 ctx = new gfxContext(dt);
michael@0 255 }
michael@0 256 ctx->Translate(-gfxPoint(destRect.x, destRect.y));
michael@0 257 context = new nsRenderingContext();
michael@0 258 context->Init(aCtx->DeviceContext(), ctx);
michael@0 259 }
michael@0 260 }
michael@0 261 #endif
michael@0 262
michael@0 263 PaintInternal(aBuilder,
michael@0 264 (surf || dt) ? context.get() : aCtx,
michael@0 265 (surf || dt) ? bgClipRect: mVisibleRect,
michael@0 266 &bgClipRect);
michael@0 267
michael@0 268 if (surf) {
michael@0 269 BlitSurface(dest, destRect, surf);
michael@0 270 frame->Properties().Set(nsIFrame::CachedBackgroundImage(),
michael@0 271 surf.forget().take());
michael@0 272 }
michael@0 273 if (dt) {
michael@0 274 BlitSurface(dest->GetDrawTarget(), destRect, dt);
michael@0 275 frame->Properties().Set(nsIFrame::CachedBackgroundImageDT(), dt.forget().drop());
michael@0 276 }
michael@0 277 }
michael@0 278
michael@0 279 void
michael@0 280 nsDisplayCanvasThemedBackground::Paint(nsDisplayListBuilder* aBuilder,
michael@0 281 nsRenderingContext* aCtx)
michael@0 282 {
michael@0 283 nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
michael@0 284 nsPoint offset = ToReferenceFrame();
michael@0 285 nsRect bgClipRect = frame->CanvasArea() + offset;
michael@0 286
michael@0 287 PaintInternal(aBuilder, aCtx, mVisibleRect, &bgClipRect);
michael@0 288 }
michael@0 289
michael@0 290 /**
michael@0 291 * A display item to paint the focus ring for the document.
michael@0 292 *
michael@0 293 * The only reason this can't use nsDisplayGeneric is overriding GetBounds.
michael@0 294 */
michael@0 295 class nsDisplayCanvasFocus : public nsDisplayItem {
michael@0 296 public:
michael@0 297 nsDisplayCanvasFocus(nsDisplayListBuilder* aBuilder, nsCanvasFrame *aFrame)
michael@0 298 : nsDisplayItem(aBuilder, aFrame)
michael@0 299 {
michael@0 300 MOZ_COUNT_CTOR(nsDisplayCanvasFocus);
michael@0 301 }
michael@0 302 virtual ~nsDisplayCanvasFocus() {
michael@0 303 MOZ_COUNT_DTOR(nsDisplayCanvasFocus);
michael@0 304 }
michael@0 305
michael@0 306 virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
michael@0 307 bool* aSnap) MOZ_OVERRIDE
michael@0 308 {
michael@0 309 *aSnap = false;
michael@0 310 // This is an overestimate, but that's not a problem.
michael@0 311 nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
michael@0 312 return frame->CanvasArea() + ToReferenceFrame();
michael@0 313 }
michael@0 314
michael@0 315 virtual void Paint(nsDisplayListBuilder* aBuilder,
michael@0 316 nsRenderingContext* aCtx) MOZ_OVERRIDE
michael@0 317 {
michael@0 318 nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
michael@0 319 frame->PaintFocus(*aCtx, ToReferenceFrame());
michael@0 320 }
michael@0 321
michael@0 322 NS_DISPLAY_DECL_NAME("CanvasFocus", TYPE_CANVAS_FOCUS)
michael@0 323 };
michael@0 324
michael@0 325 void
michael@0 326 nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
michael@0 327 const nsRect& aDirtyRect,
michael@0 328 const nsDisplayListSet& aLists)
michael@0 329 {
michael@0 330 if (GetPrevInFlow()) {
michael@0 331 DisplayOverflowContainers(aBuilder, aDirtyRect, aLists);
michael@0 332 }
michael@0 333
michael@0 334 // Force a background to be shown. We may have a background propagated to us,
michael@0 335 // in which case StyleBackground wouldn't have the right background
michael@0 336 // and the code in nsFrame::DisplayBorderBackgroundOutline might not give us
michael@0 337 // a background.
michael@0 338 // We don't have any border or outline, and our background draws over
michael@0 339 // the overflow area, so just add nsDisplayCanvasBackground instead of
michael@0 340 // calling DisplayBorderBackgroundOutline.
michael@0 341 if (IsVisibleForPainting(aBuilder)) {
michael@0 342 nsStyleContext* bgSC;
michael@0 343 const nsStyleBackground* bg = nullptr;
michael@0 344 bool isThemed = IsThemed();
michael@0 345 if (!isThemed && nsCSSRendering::FindBackground(this, &bgSC)) {
michael@0 346 bg = bgSC->StyleBackground();
michael@0 347 }
michael@0 348 aLists.BorderBackground()->AppendNewToTop(
michael@0 349 new (aBuilder) nsDisplayCanvasBackgroundColor(aBuilder, this));
michael@0 350
michael@0 351 if (isThemed) {
michael@0 352 aLists.BorderBackground()->AppendNewToTop(
michael@0 353 new (aBuilder) nsDisplayCanvasThemedBackground(aBuilder, this));
michael@0 354 return;
michael@0 355 }
michael@0 356
michael@0 357 if (!bg) {
michael@0 358 return;
michael@0 359 }
michael@0 360
michael@0 361 // Create separate items for each background layer.
michael@0 362 NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
michael@0 363 if (bg->mLayers[i].mImage.IsEmpty()) {
michael@0 364 continue;
michael@0 365 }
michael@0 366 aLists.BorderBackground()->AppendNewToTop(
michael@0 367 new (aBuilder) nsDisplayCanvasBackgroundImage(aBuilder, this, i, bg));
michael@0 368 }
michael@0 369 }
michael@0 370
michael@0 371 nsIFrame* kid;
michael@0 372 for (kid = GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
michael@0 373 // Put our child into its own pseudo-stack.
michael@0 374 BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
michael@0 375 }
michael@0 376
michael@0 377 #ifdef DEBUG_CANVAS_FOCUS
michael@0 378 nsCOMPtr<nsIContent> focusContent;
michael@0 379 aPresContext->EventStateManager()->
michael@0 380 GetFocusedContent(getter_AddRefs(focusContent));
michael@0 381
michael@0 382 bool hasFocus = false;
michael@0 383 nsCOMPtr<nsISupports> container;
michael@0 384 aPresContext->GetContainer(getter_AddRefs(container));
michael@0 385 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
michael@0 386 if (docShell) {
michael@0 387 docShell->GetHasFocus(&hasFocus);
michael@0 388 printf("%p - nsCanvasFrame::Paint R:%d,%d,%d,%d DR: %d,%d,%d,%d\n", this,
michael@0 389 mRect.x, mRect.y, mRect.width, mRect.height,
michael@0 390 aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height);
michael@0 391 }
michael@0 392 printf("%p - Focus: %s c: %p DoPaint:%s\n", docShell.get(), hasFocus?"Y":"N",
michael@0 393 focusContent.get(), mDoPaintFocus?"Y":"N");
michael@0 394 #endif
michael@0 395
michael@0 396 if (!mDoPaintFocus)
michael@0 397 return;
michael@0 398 // Only paint the focus if we're visible
michael@0 399 if (!StyleVisibility()->IsVisible())
michael@0 400 return;
michael@0 401
michael@0 402 aLists.Outlines()->AppendNewToTop(new (aBuilder)
michael@0 403 nsDisplayCanvasFocus(aBuilder, this));
michael@0 404 }
michael@0 405
michael@0 406 void
michael@0 407 nsCanvasFrame::PaintFocus(nsRenderingContext& aRenderingContext, nsPoint aPt)
michael@0 408 {
michael@0 409 nsRect focusRect(aPt, GetSize());
michael@0 410
michael@0 411 nsIScrollableFrame *scrollableFrame = do_QueryFrame(GetParent());
michael@0 412 if (scrollableFrame) {
michael@0 413 nsRect portRect = scrollableFrame->GetScrollPortRect();
michael@0 414 focusRect.width = portRect.width;
michael@0 415 focusRect.height = portRect.height;
michael@0 416 focusRect.MoveBy(scrollableFrame->GetScrollPosition());
michael@0 417 }
michael@0 418
michael@0 419 // XXX use the root frame foreground color, but should we find BODY frame
michael@0 420 // for HTML documents?
michael@0 421 nsIFrame* root = mFrames.FirstChild();
michael@0 422 const nsStyleColor* color = root ? root->StyleColor() : StyleColor();
michael@0 423 if (!color) {
michael@0 424 NS_ERROR("current color cannot be found");
michael@0 425 return;
michael@0 426 }
michael@0 427
michael@0 428 nsCSSRendering::PaintFocus(PresContext(), aRenderingContext,
michael@0 429 focusRect, color->mColor);
michael@0 430 }
michael@0 431
michael@0 432 /* virtual */ nscoord
michael@0 433 nsCanvasFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
michael@0 434 {
michael@0 435 nscoord result;
michael@0 436 DISPLAY_MIN_WIDTH(this, result);
michael@0 437 if (mFrames.IsEmpty())
michael@0 438 result = 0;
michael@0 439 else
michael@0 440 result = mFrames.FirstChild()->GetMinWidth(aRenderingContext);
michael@0 441 return result;
michael@0 442 }
michael@0 443
michael@0 444 /* virtual */ nscoord
michael@0 445 nsCanvasFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
michael@0 446 {
michael@0 447 nscoord result;
michael@0 448 DISPLAY_PREF_WIDTH(this, result);
michael@0 449 if (mFrames.IsEmpty())
michael@0 450 result = 0;
michael@0 451 else
michael@0 452 result = mFrames.FirstChild()->GetPrefWidth(aRenderingContext);
michael@0 453 return result;
michael@0 454 }
michael@0 455
michael@0 456 nsresult
michael@0 457 nsCanvasFrame::Reflow(nsPresContext* aPresContext,
michael@0 458 nsHTMLReflowMetrics& aDesiredSize,
michael@0 459 const nsHTMLReflowState& aReflowState,
michael@0 460 nsReflowStatus& aStatus)
michael@0 461 {
michael@0 462 DO_GLOBAL_REFLOW_COUNT("nsCanvasFrame");
michael@0 463 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
michael@0 464 NS_FRAME_TRACE_REFLOW_IN("nsCanvasFrame::Reflow");
michael@0 465
michael@0 466 // Initialize OUT parameter
michael@0 467 aStatus = NS_FRAME_COMPLETE;
michael@0 468
michael@0 469 nsCanvasFrame* prevCanvasFrame = static_cast<nsCanvasFrame*>
michael@0 470 (GetPrevInFlow());
michael@0 471 if (prevCanvasFrame) {
michael@0 472 AutoFrameListPtr overflow(aPresContext,
michael@0 473 prevCanvasFrame->StealOverflowFrames());
michael@0 474 if (overflow) {
michael@0 475 NS_ASSERTION(overflow->OnlyChild(),
michael@0 476 "must have doc root as canvas frame's only child");
michael@0 477 nsContainerFrame::ReparentFrameViewList(*overflow, prevCanvasFrame, this);
michael@0 478 // Prepend overflow to the our child list. There may already be
michael@0 479 // children placeholders for fixed-pos elements, which don't get
michael@0 480 // reflowed but must not be lost until the canvas frame is destroyed.
michael@0 481 mFrames.InsertFrames(this, nullptr, *overflow);
michael@0 482 }
michael@0 483 }
michael@0 484
michael@0 485 // Set our size up front, since some parts of reflow depend on it
michael@0 486 // being already set. Note that the computed height may be
michael@0 487 // unconstrained; that's ok. Consumers should watch out for that.
michael@0 488 SetSize(nsSize(aReflowState.ComputedWidth(), aReflowState.ComputedHeight()));
michael@0 489
michael@0 490 // Reflow our one and only normal child frame. It's either the root
michael@0 491 // element's frame or a placeholder for that frame, if the root element
michael@0 492 // is abs-pos or fixed-pos. We may have additional children which
michael@0 493 // are placeholders for continuations of fixed-pos content, but those
michael@0 494 // don't need to be reflowed. The normal child is always comes before
michael@0 495 // the fixed-pos placeholders, because we insert it at the start
michael@0 496 // of the child list, above.
michael@0 497 nsHTMLReflowMetrics kidDesiredSize(aReflowState);
michael@0 498 if (mFrames.IsEmpty()) {
michael@0 499 // We have no child frame, so return an empty size
michael@0 500 aDesiredSize.Width() = aDesiredSize.Height() = 0;
michael@0 501 } else {
michael@0 502 nsIFrame* kidFrame = mFrames.FirstChild();
michael@0 503 bool kidDirty = (kidFrame->GetStateBits() & NS_FRAME_IS_DIRTY) != 0;
michael@0 504
michael@0 505 nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame,
michael@0 506 nsSize(aReflowState.AvailableWidth(),
michael@0 507 aReflowState.AvailableHeight()));
michael@0 508
michael@0 509 if (aReflowState.mFlags.mVResize &&
michael@0 510 (kidFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT)) {
michael@0 511 // Tell our kid it's being vertically resized too. Bit of a
michael@0 512 // hack for framesets.
michael@0 513 kidReflowState.mFlags.mVResize = true;
michael@0 514 }
michael@0 515
michael@0 516 nsPoint kidPt(kidReflowState.ComputedPhysicalMargin().left,
michael@0 517 kidReflowState.ComputedPhysicalMargin().top);
michael@0 518
michael@0 519 kidReflowState.ApplyRelativePositioning(&kidPt);
michael@0 520
michael@0 521 // Reflow the frame
michael@0 522 ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState,
michael@0 523 kidPt.x, kidPt.y, 0, aStatus);
michael@0 524
michael@0 525 // Complete the reflow and position and size the child frame
michael@0 526 FinishReflowChild(kidFrame, aPresContext, kidDesiredSize, &kidReflowState,
michael@0 527 kidPt.x, kidPt.y, 0);
michael@0 528
michael@0 529 if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
michael@0 530 nsIFrame* nextFrame = kidFrame->GetNextInFlow();
michael@0 531 NS_ASSERTION(nextFrame || aStatus & NS_FRAME_REFLOW_NEXTINFLOW,
michael@0 532 "If it's incomplete and has no nif yet, it must flag a nif reflow.");
michael@0 533 if (!nextFrame) {
michael@0 534 nextFrame = aPresContext->PresShell()->FrameConstructor()->
michael@0 535 CreateContinuingFrame(aPresContext, kidFrame, this);
michael@0 536 SetOverflowFrames(nsFrameList(nextFrame, nextFrame));
michael@0 537 // Root overflow containers will be normal children of
michael@0 538 // the canvas frame, but that's ok because there
michael@0 539 // aren't any other frames we need to isolate them from
michael@0 540 // during reflow.
michael@0 541 }
michael@0 542 if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
michael@0 543 nextFrame->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
michael@0 544 }
michael@0 545 }
michael@0 546
michael@0 547 // If the child frame was just inserted, then we're responsible for making sure
michael@0 548 // it repaints
michael@0 549 if (kidDirty) {
michael@0 550 // But we have a new child, which will affect our background, so
michael@0 551 // invalidate our whole rect.
michael@0 552 // Note: Even though we request to be sized to our child's size, our
michael@0 553 // scroll frame ensures that we are always the size of the viewport.
michael@0 554 // Also note: GetPosition() on a CanvasFrame is always going to return
michael@0 555 // (0, 0). We only want to invalidate GetRect() since Get*OverflowRect()
michael@0 556 // could also include overflow to our top and left (out of the viewport)
michael@0 557 // which doesn't need to be painted.
michael@0 558 nsIFrame* viewport = PresContext()->GetPresShell()->GetRootFrame();
michael@0 559 viewport->InvalidateFrame();
michael@0 560 }
michael@0 561
michael@0 562 // Return our desired size. Normally it's what we're told, but
michael@0 563 // sometimes we can be given an unconstrained height (when a window
michael@0 564 // is sizing-to-content), and we should compute our desired height.
michael@0 565 aDesiredSize.Width() = aReflowState.ComputedWidth();
michael@0 566 if (aReflowState.ComputedHeight() == NS_UNCONSTRAINEDSIZE) {
michael@0 567 aDesiredSize.Height() = kidFrame->GetRect().height +
michael@0 568 kidReflowState.ComputedPhysicalMargin().TopBottom();
michael@0 569 } else {
michael@0 570 aDesiredSize.Height() = aReflowState.ComputedHeight();
michael@0 571 }
michael@0 572
michael@0 573 aDesiredSize.SetOverflowAreasToDesiredBounds();
michael@0 574 aDesiredSize.mOverflowAreas.UnionWith(
michael@0 575 kidDesiredSize.mOverflowAreas + kidPt);
michael@0 576 }
michael@0 577
michael@0 578 if (prevCanvasFrame) {
michael@0 579 ReflowOverflowContainerChildren(aPresContext, aReflowState,
michael@0 580 aDesiredSize.mOverflowAreas, 0,
michael@0 581 aStatus);
michael@0 582 }
michael@0 583
michael@0 584 FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);
michael@0 585
michael@0 586 NS_FRAME_TRACE_REFLOW_OUT("nsCanvasFrame::Reflow", aStatus);
michael@0 587 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
michael@0 588 return NS_OK;
michael@0 589 }
michael@0 590
michael@0 591 nsIAtom*
michael@0 592 nsCanvasFrame::GetType() const
michael@0 593 {
michael@0 594 return nsGkAtoms::canvasFrame;
michael@0 595 }
michael@0 596
michael@0 597 nsresult
michael@0 598 nsCanvasFrame::GetContentForEvent(WidgetEvent* aEvent,
michael@0 599 nsIContent** aContent)
michael@0 600 {
michael@0 601 NS_ENSURE_ARG_POINTER(aContent);
michael@0 602 nsresult rv = nsFrame::GetContentForEvent(aEvent,
michael@0 603 aContent);
michael@0 604 if (NS_FAILED(rv) || !*aContent) {
michael@0 605 nsIFrame* kid = mFrames.FirstChild();
michael@0 606 if (kid) {
michael@0 607 rv = kid->GetContentForEvent(aEvent,
michael@0 608 aContent);
michael@0 609 }
michael@0 610 }
michael@0 611
michael@0 612 return rv;
michael@0 613 }
michael@0 614
michael@0 615 #ifdef DEBUG_FRAME_DUMP
michael@0 616 nsresult
michael@0 617 nsCanvasFrame::GetFrameName(nsAString& aResult) const
michael@0 618 {
michael@0 619 return MakeFrameName(NS_LITERAL_STRING("Canvas"), aResult);
michael@0 620 }
michael@0 621 #endif

mercurial