Commit 8f1f1d1f authored by Timothy Nikkel's avatar Timothy Nikkel
Browse files

Bug 488242. Make iframes with semi-transparent backgrounds work correctly by...

Bug 488242. Make iframes with semi-transparent backgrounds work correctly by painting all canvas background colors using a dedicated fallback background color display item. r+sr=roc
parent 9562cc80
Loading
Loading
Loading
Loading
+92 −46
Original line number Diff line number Diff line
@@ -310,8 +310,7 @@ static void PaintBackgroundLayer(nsPresContext* aPresContext,
                                 const nsRect& aBGClipRect,
                                 const nsStyleBackground& aBackground,
                                 const nsStyleBackground::Layer& aLayer,
                                 const nsStyleBorder& aBorder,
                                 PRBool aUsePrintSettings);
                                 const nsStyleBorder& aBorder);

static void DrawBorderImage(nsPresContext* aPresContext,
                            nsIRenderingContext& aRenderingContext,
@@ -1332,9 +1331,9 @@ nsCSSRendering::PaintBackground(nsPresContext* aPresContext,
  NS_PRECONDITION(aForFrame,
                  "Frame is expected to be provided to PaintBackground");

  const nsStyleBackground *color;
  if (!FindBackground(aPresContext, aForFrame, &color)) {
    // we don't want to bail out of moz-appearance is set on a root
  const nsStyleBackground *background;
  if (!FindBackground(aPresContext, aForFrame, &background)) {
    // We don't want to bail out if moz-appearance is set on a root
    // node. If it has a parent content node, bail because it's not
    // a root, other wise keep going in order to let the theme stuff
    // draw the background. The canvas really should be drawing the
@@ -1348,11 +1347,11 @@ nsCSSRendering::PaintBackground(nsPresContext* aPresContext,
      return;
    }

    color = aForFrame->GetStyleBackground();
    background = aForFrame->GetStyleBackground();
  }

  PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame,
                        aDirtyRect, aBorderArea, *color,
                        aDirtyRect, aBorderArea, *background,
                        *aForFrame->GetStyleBorder(), aFlags,
                        aBGClipRect);
}
@@ -1496,13 +1495,71 @@ SetupBackgroundClip(gfxContext *aCtx, PRUint8 aBackgroundClip,
  }
}

static nscolor
DetermineBackgroundColorInternal(nsPresContext* aPresContext,
                                 const nsStyleBackground& aBackground,
                                 nsIFrame* aFrame,
                                 PRBool* aDrawBackgroundImage,
                                 PRBool* aDrawBackgroundColor,
                                 nsCOMPtr<imgIRequest>& aBottomImage)
{
  *aDrawBackgroundImage = PR_TRUE;
  *aDrawBackgroundColor = PR_TRUE;

  if (aFrame->HonorPrintBackgroundSettings()) {
    *aDrawBackgroundImage = aPresContext->GetBackgroundImageDraw();
    *aDrawBackgroundColor = aPresContext->GetBackgroundColorDraw();
  }

  aBottomImage = aBackground.BottomLayer().mImage;

  if (!aDrawBackgroundImage || !UseImageRequestForBackground(aBottomImage)) {
    aBottomImage = nsnull;
  }

  nscolor bgColor;
  if (*aDrawBackgroundColor) {
    bgColor = aBackground.mBackgroundColor;
    if (NS_GET_A(bgColor) == 0)
      *aDrawBackgroundColor = PR_FALSE;
  } else {
    // If GetBackgroundColorDraw() is false, we are still expected to
    // draw color in the background of any frame that's not completely
    // transparent, but we are expected to use white instead of whatever
    // color was specified.
    bgColor = NS_RGB(255, 255, 255);
    if (*aDrawBackgroundImage || !aBackground.IsTransparent())
      *aDrawBackgroundColor = PR_TRUE;
    else
      bgColor = NS_RGBA(0,0,0,0);
  }

  return bgColor;
}

nscolor
nsCSSRendering::DetermineBackgroundColor(nsPresContext* aPresContext,
                                         const nsStyleBackground& aBackground,
                                         nsIFrame* aFrame)
{
  PRBool drawBackgroundImage;
  PRBool drawBackgroundColor;
  nsCOMPtr<imgIRequest> bottomImage;
  return DetermineBackgroundColorInternal(aPresContext,
                                          aBackground,
                                          aFrame,
                                          &drawBackgroundImage,
                                          &drawBackgroundColor,
                                          bottomImage);
}

void
nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
                                      nsIRenderingContext& aRenderingContext,
                                      nsIFrame* aForFrame,
                                      const nsRect& aDirtyRect,
                                      const nsRect& aBorderArea,
                                      const nsStyleBackground& aColor,
                                      const nsStyleBackground& aBackground,
                                      const nsStyleBorder& aBorder,
                                      PRUint32 aFlags,
                                      nsRect* aBGClipRect)
@@ -1526,35 +1583,25 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
    }
  }

  // For canvas frames (in the CSS sense) we draw the background color using
  // a solid color item that gets added in nsLayoutUtils::PaintFrame,
  // PresShell::RenderDocument, or nsSubDocumentFrame::BuildDisplayList
  // (bug 488242).
  PRBool isCanvasFrame = IsCanvasFrame(aForFrame);

  // Determine whether we are drawing background images and/or
  // background colors.
  PRBool drawBackgroundImage = PR_TRUE;
  PRBool drawBackgroundColor = PR_TRUE;
  PRBool usePrintSettings = aForFrame->HonorPrintBackgroundSettings();
  if (usePrintSettings) {
    drawBackgroundImage = aPresContext->GetBackgroundImageDraw();
    drawBackgroundColor = aPresContext->GetBackgroundColorDraw();
  }
  PRBool drawBackgroundImage;
  PRBool drawBackgroundColor;

  imgIRequest *bottomImage = aColor.BottomLayer().mImage;
  if (!drawBackgroundImage || !UseImageRequestForBackground(bottomImage)) {
    bottomImage = nsnull;
  }
  nsCOMPtr<imgIRequest> bottomImage;

  // If GetBackgroundColorDraw() is false, we are still expected to
  // draw color in the background of any frame that's not completely
  // transparent, but we are expected to use white instead of whatever
  // color was specified.
  nscolor bgColor;
  if (drawBackgroundColor) {
    bgColor = aColor.mBackgroundColor;
    if (NS_GET_A(bgColor) == 0)
      drawBackgroundColor = PR_FALSE;
  } else {
    bgColor = NS_RGB(255, 255, 255);
    if (drawBackgroundImage || !aColor.IsTransparent())
      drawBackgroundColor = PR_TRUE;
  }
  nscolor bgColor = DetermineBackgroundColorInternal(aPresContext,
                                                     aBackground,
                                                     aForFrame,
                                                     &drawBackgroundImage,
                                                     &drawBackgroundColor,
                                                     bottomImage);

  // At this point, drawBackgroundImage and drawBackgroundColor are
  // true if and only if we are actually supposed to paint an image or
@@ -1603,7 +1650,7 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
    // radii as the border code will.
    // The background-color is drawn based on the bottom
    // background-clip.
    currentBackgroundClip = aColor.BottomLayer().mClip;
    currentBackgroundClip = aBackground.BottomLayer().mClip;
    isSolidBorder =
      (aFlags & PAINT_WILL_PAINT_BORDER) && IsSolidBorder(aBorder);
    if (isSolidBorder)
@@ -1615,14 +1662,14 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
  }

  // If we might be using a background color, go ahead and set it now.
  if (drawBackgroundColor)
  if (drawBackgroundColor && !isCanvasFrame)
    ctx->SetColor(gfxRGBA(bgColor));

  // If there is no background image, draw a color.  (If there is
  // neither a background image nor a color, we wouldn't have gotten
  // this far.)
  if (!drawBackgroundImage) {
    if (!dirtyRectGfx.IsEmpty()) {
    if (!dirtyRectGfx.IsEmpty() && !isCanvasFrame) {
      ctx->NewPath();
      ctx->Rectangle(dirtyRectGfx, PR_TRUE);
      ctx->Fill();
@@ -1633,10 +1680,10 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
  // Ensure we get invalidated for loads of the image.  We need to do
  // this here because this might be the only code that knows about the
  // association of the style data with the frame.
  aPresContext->SetupBackgroundImageLoaders(aForFrame, &aColor);
  aPresContext->SetupBackgroundImageLoaders(aForFrame, &aBackground);

  if (bottomImage &&
      aColor.BottomLayer().mRepeat == NS_STYLE_BG_REPEAT_XY &&
      aBackground.BottomLayer().mRepeat == NS_STYLE_BG_REPEAT_XY &&
      drawBackgroundColor) {
    nsCOMPtr<imgIContainer> image;
    bottomImage->GetImage(getter_AddRefs(image));
@@ -1665,7 +1712,7 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,

  // The background color is rendered over the entire dirty area,
  // even if the image isn't.
  if (drawBackgroundColor) {
  if (drawBackgroundColor && !isCanvasFrame) {
    if (!dirtyRectGfx.IsEmpty()) {
      ctx->NewPath();
      ctx->Rectangle(dirtyRectGfx, PR_TRUE);
@@ -1674,8 +1721,8 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
  }

  if (drawBackgroundImage) {
    NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, &aColor) {
      const nsStyleBackground::Layer &layer = aColor.mLayers[i];
    NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, &aBackground) {
      const nsStyleBackground::Layer &layer = aBackground.mLayers[i];
      if (!aBGClipRect) {
        PRUint8 newBackgroundClip =
          isSolidBorder ? NS_STYLE_BG_CLIP_PADDING : layer.mClip;
@@ -1689,8 +1736,8 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
      }
      if (!dirtyRectGfx.IsEmpty()) {
        PaintBackgroundLayer(aPresContext, aRenderingContext, aForFrame,
                             dirtyRect, aBorderArea, bgClipArea, aColor,
                             layer, aBorder, usePrintSettings);
                             dirtyRect, aBorderArea, bgClipArea, aBackground,
                             layer, aBorder);
      }
    }
  }
@@ -1705,8 +1752,7 @@ PaintBackgroundLayer(nsPresContext* aPresContext,
                     const nsRect& aBGClipRect,
                     const nsStyleBackground& aBackground,
                     const nsStyleBackground::Layer& aLayer,
                     const nsStyleBorder& aBorder,
                     PRBool aUsePrintSettings)
                     const nsStyleBorder& aBorder)
{
  // Lookup the image
  imgIRequest *req = aLayer.mImage;
+9 −1
Original line number Diff line number Diff line
@@ -167,6 +167,14 @@ struct nsCSSRendering {
  FindNonTransparentBackground(nsStyleContext* aContext,
                               PRBool aStartAtParent = PR_FALSE);

  /**
   * Determine the background color to draw taking into account print settings.
   */
  static nscolor
  DetermineBackgroundColor(nsPresContext* aPresContext,
                           const nsStyleBackground& aBackground,
                           nsIFrame* aFrame);

  /**
   * Render the background for an element using css rendering rules
   * for backgrounds.
@@ -199,7 +207,7 @@ struct nsCSSRendering {
                                    nsIFrame* aForFrame,
                                    const nsRect& aDirtyRect,
                                    const nsRect& aBorderArea,
                                    const nsStyleBackground& aColor,
                                    const nsStyleBackground& aBackground,
                                    const nsStyleBorder& aBorder,
                                    PRUint32 aFlags,
                                    nsRect* aBGClipRect = nsnull);
+2 −1
Original line number Diff line number Diff line
@@ -546,7 +546,8 @@ nsDisplayBackground::IsOpaque(nsDisplayListBuilder* aBuilder) {
      nsLayoutUtils::HasNonZeroCorner(mFrame->GetStyleBorder()->mBorderRadius))
    return PR_FALSE;

  if (NS_GET_A(bg->mBackgroundColor) == 255)
  if (NS_GET_A(bg->mBackgroundColor) == 255 &&
      !nsCSSRendering::IsCanvasFrame(mFrame))
    return PR_TRUE;

  if (bottomLayer.mRepeat == NS_STYLE_BG_REPEAT_XY) {
+12 −16
Original line number Diff line number Diff line
@@ -125,11 +125,6 @@ public:
   * determine which frame is under the mouse position
   * @param aBuildCaret whether or not we should include the caret in any
   * display lists that we make.
   * @param aMovingFrame a frame whose subtree should be regarded as
   * moving; moving frames are not allowed to clip or cover (during
   * OptimizeVisibility) non-moving frames. E.g. when we're constructing
   * a display list to see what should be repainted during a scroll
   * operation, we specify the scrolled frame as the moving frame.
   */
  nsDisplayListBuilder(nsIFrame* aReferenceFrame, PRBool aIsForEvents,
                       PRBool aBuildCaret);
@@ -162,7 +157,10 @@ public:
  /**
   * Indicate that we'll use this display list to analyze the effects
   * of aMovingFrame moving by aMoveDelta. The move has already been
   * applied to the frame tree.
   * applied to the frame tree. Moving frames are not allowed to clip or
   * cover (during OptimizeVisibility) non-moving frames. E.g. when we're
   * constructing a display list to see what should be repainted during a
   * scroll operation, we specify the scrolled frame as the moving frame.
   */
  void SetMovingFrame(nsIFrame* aMovingFrame, const nsPoint& aMoveDelta) {
    mMovingFrame = aMovingFrame;
@@ -512,9 +510,6 @@ protected:
    mAbove = nsnull;
  }
  
  static PRBool ComputeVisibilityFromBounds(nsIFrame* aFrame,
      const nsRect& aRect, nsRegion& aCovered, PRBool aIsOpaque);

  nsIFrame* mFrame;
};

@@ -1011,13 +1006,14 @@ public:

/**
 * A simple display item that just renders a solid color across the
 * specified bounds. Used in cases where we can't draw the frame tree but
 * we want to draw something to avoid an ugly flash of white when
 * navigating between pages. Also used as a bottom item to ensure that
 * something is painted everywhere. The bounds can differ from the frame's
 * bounds -- this is needed when a frame/iframe is loading and there is not
 * yet a frame tree to go in the frame/iframe so we use the subdoc frame
 * of the parent document as a standin.
 * specified bounds. For canvas frames (in the CSS sense) we split off the
 * drawing of the background color into this class (from nsDisplayBackground
 * via nsDisplayCanvasBackground). This is done so that we can always draw a
 * background color to avoid ugly flashes of white when we can't draw a full
 * frame tree (ie when a page is loading). The bounds can differ from the
 * frame's bounds -- this is needed when a frame/iframe is loading and there
 * is not yet a frame tree to go in the frame/iframe so we use the subdoc
 * frame of the parent document as a standin.
 */
class nsDisplaySolidColor : public nsDisplayItem {
public:
+26 −11
Original line number Diff line number Diff line
@@ -98,14 +98,15 @@ class gfxASurface;
class gfxContext;
class nsPIDOMEventTarget;
class nsIDOMEvent;
class nsDisplayList;
class nsDisplayListBuilder;

typedef short SelectionType;
typedef PRUint32 nsFrameState;

// 189d234b-3823-4e8f-bbd2-63c0282b9fac
#define NS_IPRESSHELL_IID \
  { 0x189d234b, 0x3823, 0x4e8f, \
    { 0xbb, 0xd2, 0x63, 0xc0, 0x28, 0x2b, 0x9f, 0xac } }
{ 0x5039364e, 0x6e3e, 0x4aae, \
  { 0xb8, 0xac, 0xf1, 0xee, 0xf1, 0xcb, 0x85, 0x45 } }

// Constants for ScrollContentIntoView() function
#define NS_PRESSHELL_SCROLL_TOP      0
@@ -772,7 +773,7 @@ public:
                                                   nsIntPoint& aPoint,
                                                   nsIntRect* aScreenRect) = 0;

  /*
  /**
   * Renders a selection to a surface and returns it. This method is primarily
   * intended to create the drag feedback when dragging a selection.
   *
@@ -807,20 +808,34 @@ public:
   */
  NS_IMETHOD DisableNonTestMouseEvents(PRBool aDisable) = 0;

  /* Record the background color of the most recently loaded canvas.
   * This color is composited on top of the user's default background
   * color whenever we need to provide an "ultimate" background color.
   * See PresShell::Paint, PresShell::PaintDefaultBackground, and
   * nsDocShell::SetupNewViewer; bug 476557 and other bugs mentioned there.
  /**
   * Record the background color of the most recently drawn canvas. This color
   * is composited on top of the user's default background color and then used
   * to draw the background color of the canvas. See PresShell::Paint,
   * PresShell::PaintDefaultBackground, and nsDocShell::SetupNewViewer;
   * bug 488242, bug 476557 and other bugs mentioned there.
   */
  void SetCanvasBackground(nscolor aColor) { mCanvasBackgroundColor = aColor; }
  nscolor GetCanvasBackground() { return mCanvasBackgroundColor; }

  /* Use the current frame tree (if it exists) to update the background
   * color of the most recent canvas.
  /**
   * Use the current frame tree (if it exists) to update the background
   * color of the most recently drawn canvas.
   */
  virtual void UpdateCanvasBackground() = 0;

  /**
   * Add a solid color item to the bottom of aList with frame aFrame and
   * bounds aBounds. If aBounds is null (the default) then the bounds
   * will be derived from the frame. aBackstopColor is composed behind
   * the background color of the canvas, it is transparent by default.
   */
  virtual nsresult AddCanvasBackgroundColorItem(nsDisplayListBuilder& aBuilder,
                                                nsDisplayList& aList,
                                                nsIFrame* aFrame,
                                                nsRect* aBounds = nsnull,
                                                nscolor aBackstopColor = NS_RGBA(0,0,0,0)) = 0;

  void ObserveNativeAnonMutationsForPrint(PRBool aObserve)
  {
    mObservesMutationsForPrint = aObserve;
Loading