layout/painting/nsCSSRenderingBorders.h
author alwu <alwu@mozilla.com>
Mon, 07 Jan 2019 19:57:48 +0000
changeset 512757 0e229bbdaae5c8fa9f83796c628a4fdf88f057ba
parent 512746 ee870d4a43083769491e0964ae180304542fc10f
child 514505 5f4630838d46dd81dadb13220a4af0da9e23a619
permissions -rw-r--r--
Bug 1513039 - part5 : log warning when autoplay is blocked. r=cpearce,karlt Wrap 'nsContentUtils::ReportToConsole()' to reduce necessary input parameters and call it when we need to log error or warning message. Show the warning when autoplay is blocked. For web audio, this restores the console messages removed in part4 and also reports the same message when the AudioContext is blocked in the constructor. Differential Revision: https://phabricator.services.mozilla.com/D14330

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef NS_CSS_RENDERING_BORDERS_H
#define NS_CSS_RENDERING_BORDERS_H

#include "gfxRect.h"
#include "mozilla/Attributes.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/BezierUtils.h"
#include "mozilla/gfx/PathHelpers.h"
#include "mozilla/RefPtr.h"
#include "nsColor.h"
#include "nsCOMPtr.h"
#include "nsIFrame.h"
#include "nsImageRenderer.h"
#include "nsStyleConsts.h"
#include "nsStyleStruct.h"
#include "nsPresContext.h"
#include "gfxUtils.h"

struct nsBorderColors;
class nsDisplayBorder;

namespace mozilla {
namespace gfx {
class GradientStops;
}  // namespace gfx
namespace layers {
class StackingContextHelper;
}  // namespace layers
}  // namespace mozilla

// define this to enable a bunch of debug dump info
#undef DEBUG_NEW_BORDERS

/*
 * Helper class that handles border rendering.
 *
 * aDrawTarget -- the DrawTarget to which the border should be rendered
 * outsideRect -- the rectangle on the outer edge of the border
 *
 * For any parameter where an array of side values is passed in,
 * they are in top, right, bottom, left order.
 *
 * borderStyles -- one border style enum per side
 * borderWidths -- one border width per side
 * borderRadii -- a RectCornerRadii struct describing the w/h for each rounded
 * corner. If the corner doesn't have a border radius, 0,0 should be given for
 * it. borderColors -- one nscolor per side
 *
 * skipSides -- a bit mask specifying which sides, if any, to skip
 * backgroundColor -- the background color of the element.
 *    Used in calculating colors for 2-tone borders, such as inset and outset
 * gapRect - a rectangle that should be clipped out to leave a gap in a border,
 *    or nullptr if none.
 */

typedef enum {
  BorderColorStyleNone,
  BorderColorStyleSolid,
  BorderColorStyleLight,
  BorderColorStyleDark
} BorderColorStyle;

class nsPresContext;

class nsCSSBorderRenderer final {
  typedef mozilla::gfx::Bezier Bezier;
  typedef mozilla::gfx::ColorPattern ColorPattern;
  typedef mozilla::gfx::DrawTarget DrawTarget;
  typedef mozilla::gfx::Float Float;
  typedef mozilla::gfx::Path Path;
  typedef mozilla::gfx::Point Point;
  typedef mozilla::gfx::Rect Rect;
  typedef mozilla::gfx::RectCornerRadii RectCornerRadii;
  typedef mozilla::gfx::StrokeOptions StrokeOptions;

  friend class nsDisplayBorder;
  friend class nsDisplayOutline;
  friend class nsDisplayButtonBorder;
  friend class nsDisplayButtonForeground;

 public:
  nsCSSBorderRenderer(nsPresContext* aPresContext,
                      const mozilla::dom::Document* aDocument,
                      DrawTarget* aDrawTarget, const Rect& aDirtyRect,
                      Rect& aOuterRect,
                      const mozilla::StyleBorderStyle* aBorderStyles,
                      const Float* aBorderWidths, RectCornerRadii& aBorderRadii,
                      const nscolor* aBorderColors, bool aBackfaceIsVisible,
                      const mozilla::Maybe<Rect>& aClipRect);

  // draw the entire border
  void DrawBorders();

  void CreateWebRenderCommands(
      nsDisplayItem* aItem, mozilla::wr::DisplayListBuilder& aBuilder,
      mozilla::wr::IpcResourceUpdateQueue& aResources,
      const mozilla::layers::StackingContextHelper& aSc);

  // utility function used for background painting as well as borders
  static void ComputeInnerRadii(const RectCornerRadii& aRadii,
                                const Float* aBorderSizes,
                                RectCornerRadii* aInnerRadiiRet);

  // Given aRadii as the border radii for a rectangle, compute the
  // appropriate radii for another rectangle *outside* that rectangle
  // by increasing the radii, except keeping sharp corners sharp.
  // Used for spread box-shadows
  static void ComputeOuterRadii(const RectCornerRadii& aRadii,
                                const Float* aBorderSizes,
                                RectCornerRadii* aOuterRadiiRet);

  static bool AllCornersZeroSize(const RectCornerRadii& corners);

 private:
  RectCornerRadii mBorderCornerDimensions;

  // Target document to report warning
  nsPresContext* mPresContext;
  const mozilla::dom::Document* mDocument;

  // destination DrawTarget and dirty rect
  DrawTarget* mDrawTarget;
  Rect mDirtyRect;

  // the rectangle of the outside and the inside of the border
  Rect mOuterRect;
  Rect mInnerRect;

  // the style and size of the border
  mozilla::StyleBorderStyle mBorderStyles[4];
  Float mBorderWidths[4];
  RectCornerRadii mBorderRadii;

  // the colors for 'border-top-color' et. al.
  nscolor mBorderColors[4];

  // calculated values
  bool mAllBordersSameStyle;
  bool mAllBordersSameWidth;
  bool mOneUnitBorder;
  bool mNoBorderRadius;
  bool mAvoidStroke;
  bool mBackfaceIsVisible;
  mozilla::Maybe<Rect> mLocalClip;

  // For all the sides in the bitmask, would they be rendered
  // in an identical color and style?
  bool AreBorderSideFinalStylesSame(uint8_t aSides);

  // For the given style, is the given corner a solid color?
  bool IsSolidCornerStyle(mozilla::StyleBorderStyle aStyle,
                          mozilla::Corner aCorner);

  // For the given corner, is the given corner mergeable into one dot?
  bool IsCornerMergeable(mozilla::Corner aCorner);

  // For the given solid corner, what color style should be used?
  BorderColorStyle BorderColorStyleForSolidCorner(
      mozilla::StyleBorderStyle aStyle, mozilla::Corner aCorner);

  //
  // Path generation functions
  //

  // Get the Rect for drawing the given corner
  Rect GetCornerRect(mozilla::Corner aCorner);
  // add the path for drawing the given side without any adjacent corners to the
  // context
  Rect GetSideClipWithoutCornersRect(mozilla::Side aSide);

  // Create a clip path for the wedge that this side of
  // the border should take up.  This is only called
  // when we're drawing separate border sides, so we know
  // that ADD compositing is taking place.
  //
  // This code needs to make sure that the individual pieces
  // don't ever (mathematically) overlap; the pixel overlap
  // is taken care of by the ADD compositing.
  already_AddRefed<Path> GetSideClipSubPath(mozilla::Side aSide);

  // Return start or end point for dashed/dotted side
  Point GetStraightBorderPoint(mozilla::Side aSide, mozilla::Corner aCorner,
                               bool* aIsUnfilled, Float aDotOffset = 0.0f);

  // Return bezier control points for the outer and the inner curve for given
  // corner
  void GetOuterAndInnerBezier(Bezier* aOuterBezier, Bezier* aInnerBezier,
                              mozilla::Corner aCorner);

  // Given a set of sides to fill and a color, do so in the fastest way.
  //
  // Stroke tends to be faster for smaller borders because it doesn't go
  // through the tessellator, which has initialization overhead.  If
  // we're rendering all sides, we can use stroke at any thickness; we
  // also do TL/BR pairs at 1px thickness using stroke.
  //
  // If we can't stroke, then if it's a TL/BR pair, we use the specific
  // TL/BR paths.  Otherwise, we do the full path and fill.
  //
  // Calling code is expected to only set up a clip as necessary; no
  // clip is needed if we can render the entire border in 1 or 2 passes.
  void FillSolidBorder(const Rect& aOuterRect, const Rect& aInnerRect,
                       const RectCornerRadii& aBorderRadii,
                       const Float* aBorderSizes, int aSides,
                       const ColorPattern& aColor);

  //
  // core rendering
  //

  // draw the border for the given sides, using the style of the first side
  // present in the bitmask
  void DrawBorderSides(int aSides);

  // Setup the stroke options for the given dashed/dotted side
  void SetupDashedOptions(StrokeOptions* aStrokeOptions, Float aDash[2],
                          mozilla::Side aSide, Float aBorderLength,
                          bool isCorner);

  // Draw the given dashed/dotte side
  void DrawDashedOrDottedSide(mozilla::Side aSide);

  // Draw the given dotted side, each dot separately
  void DrawDottedSideSlow(mozilla::Side aSide);

  // Draw the given dashed/dotted corner
  void DrawDashedOrDottedCorner(mozilla::Side aSide, mozilla::Corner aCorner);

  // Draw the given dotted corner, each segment separately
  void DrawDottedCornerSlow(mozilla::Side aSide, mozilla::Corner aCorner);

  // Draw the given dashed corner, each dot separately
  void DrawDashedCornerSlow(mozilla::Side aSide, mozilla::Corner aCorner);

  // Draw the given dashed/dotted corner with solid style
  void DrawFallbackSolidCorner(mozilla::Side aSide, mozilla::Corner aCorner);

  // Analyze if all border sides have the same width.
  bool AllBordersSameWidth();

  // Analyze if all borders are 'solid' this also considers hidden or 'none'
  // borders because they can be considered 'solid' borders of 0 width and
  // with no color effect.
  bool AllBordersSolid();

  // Draw a solid color border that is uniformly the same width.
  void DrawSingleWidthSolidBorder();

  // Draw any border which is solid on all sides.
  void DrawSolidBorder();
};

class nsCSSBorderImageRenderer final {
  typedef mozilla::nsImageRenderer nsImageRenderer;

 public:
  static mozilla::Maybe<nsCSSBorderImageRenderer> CreateBorderImageRenderer(
      nsPresContext* aPresContext, nsIFrame* aForFrame,
      const nsRect& aBorderArea, const nsStyleBorder& aStyleBorder,
      const nsRect& aDirtyRect, nsIFrame::Sides aSkipSides, uint32_t aFlags,
      mozilla::image::ImgDrawResult* aDrawResult);

  mozilla::image::ImgDrawResult DrawBorderImage(nsPresContext* aPresContext,
                                                gfxContext& aRenderingContext,
                                                nsIFrame* aForFrame,
                                                const nsRect& aDirtyRect);
  mozilla::image::ImgDrawResult CreateWebRenderCommands(
      nsDisplayItem* aItem, nsIFrame* aForFrame,
      mozilla::wr::DisplayListBuilder& aBuilder,
      mozilla::wr::IpcResourceUpdateQueue& aResources,
      const mozilla::layers::StackingContextHelper& aSc,
      mozilla::layers::RenderRootStateManager* aManager,
      nsDisplayListBuilder* aDisplayListBuilder);

  nsCSSBorderImageRenderer(const nsCSSBorderImageRenderer& aRhs);
  nsCSSBorderImageRenderer& operator=(const nsCSSBorderImageRenderer& aRhs);

 private:
  nsCSSBorderImageRenderer(nsIFrame* aForFrame, const nsRect& aBorderArea,
                           const nsStyleBorder& aStyleBorder,
                           nsIFrame::Sides aSkipSides,
                           const nsImageRenderer& aImageRenderer);

  nsImageRenderer mImageRenderer;
  nsSize mImageSize;
  nsMargin mSlice;
  nsMargin mWidths;
  nsMargin mImageOutset;
  nsRect mArea;
  nsRect mClip;
  mozilla::StyleBorderImageRepeat mRepeatModeHorizontal;
  mozilla::StyleBorderImageRepeat mRepeatModeVertical;
  uint8_t mFill;

  friend class nsDisplayBorder;
  friend struct nsCSSRendering;
};

namespace mozilla {
#ifdef DEBUG_NEW_BORDERS
#include <stdarg.h>

static inline void PrintAsString(const mozilla::gfx::Point& p) {
  fprintf(stderr, "[%f,%f]", p.x, p.y);
}

static inline void PrintAsString(const mozilla::gfx::Size& s) {
  fprintf(stderr, "[%f %f]", s.width, s.height);
}

static inline void PrintAsString(const mozilla::gfx::Rect& r) {
  fprintf(stderr, "[%f %f %f %f]", r.X(), r.Y(), r.Width(), r.Height());
}

static inline void PrintAsString(const mozilla::gfx::Float f) {
  fprintf(stderr, "%f", f);
}

static inline void PrintAsString(const char* s) { fprintf(stderr, "%s", s); }

static inline void PrintAsStringNewline(const char* s = nullptr) {
  if (s) fprintf(stderr, "%s", s);
  fprintf(stderr, "\n");
  fflush(stderr);
}

static inline MOZ_FORMAT_PRINTF(1, 2) void PrintAsFormatString(const char* fmt,
                                                               ...) {
  va_list vl;
  va_start(vl, fmt);
  vfprintf(stderr, fmt, vl);
  va_end(vl);
}

#else
static inline void PrintAsString(const mozilla::gfx::Point& p) {}
static inline void PrintAsString(const mozilla::gfx::Size& s) {}
static inline void PrintAsString(const mozilla::gfx::Rect& r) {}
static inline void PrintAsString(const mozilla::gfx::Float f) {}
static inline void PrintAsString(const char* s) {}
static inline void PrintAsStringNewline(const char* s = nullptr) {}
static inline MOZ_FORMAT_PRINTF(1, 2) void PrintAsFormatString(const char* fmt,
                                                               ...) {}
#endif

}  // namespace mozilla

#endif /* NS_CSS_RENDERING_BORDERS_H */