layout/generic/nsCanvasFrame.cpp

changeset 0
6474c204b198
     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

mercurial