DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (d38398e5144e)

VCS Links

DisplayItemClip

RoundedRect

Macros

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * 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 DISPLAYITEMCLIP_H_
#define DISPLAYITEMCLIP_H_

#include "mozilla/RefPtr.h"
#include "nsRect.h"
#include "nsTArray.h"
#include "nsStyleConsts.h"

class gfxContext;
class nsPresContext;
class nsRegion;

namespace mozilla {
namespace gfx {
class DrawTarget;
class Path;
} // namespace gfx
} // namespace mozilla

namespace mozilla {

/**
 * An DisplayItemClip represents the intersection of an optional rectangle
 * with a list of rounded rectangles (which is often empty), all in appunits.
 * It can represent everything CSS clipping can do to an element (except for
 * SVG clip-path), including no clipping at all.
 */
class DisplayItemClip {
  typedef mozilla::gfx::Color Color;
  typedef mozilla::gfx::DrawTarget DrawTarget;
  typedef mozilla::gfx::Path Path;

public:
  struct RoundedRect {
    nsRect mRect;
    // Indices into mRadii are the NS_CORNER_* constants in nsStyleConsts.h
    nscoord mRadii[8];

    RoundedRect operator+(const nsPoint& aOffset) const {
      RoundedRect r = *this;
      r.mRect += aOffset;
      return r;
    }
    bool operator==(const RoundedRect& aOther) const {
      if (!mRect.IsEqualInterior(aOther.mRect)) {
        return false;
      }

      NS_FOR_CSS_HALF_CORNERS(corner) {
        if (mRadii[corner] != aOther.mRadii[corner]) {
          return false;
        }
      }
      return true;
    }
    bool operator!=(const RoundedRect& aOther) const {
      return !(*this == aOther);
    }
  };

  // Constructs a DisplayItemClip that does no clipping at all.
  DisplayItemClip() : mHaveClipRect(false) {}

  void SetTo(const nsRect& aRect);
  void SetTo(const nsRect& aRect, const nscoord* aRadii);
  void SetTo(const nsRect& aRect, const nsRect& aRoundedRect, const nscoord* aRadii);
  void IntersectWith(const DisplayItemClip& aOther);

  // Apply this |DisplayItemClip| to the given gfxContext.  Any saving of state
  // or clearing of other clips must be done by the caller.
  // See aBegin/aEnd note on ApplyRoundedRectsTo.
  void ApplyTo(gfxContext* aContext, nsPresContext* aPresContext,
               uint32_t aBegin = 0, uint32_t aEnd = UINT32_MAX);

  void ApplyRectTo(gfxContext* aContext, int32_t A2D) const;
  // Applies the rounded rects in this Clip to aContext
  // Will only apply rounded rects from aBegin (inclusive) to aEnd
  // (exclusive) or the number of rounded rects, whichever is smaller.
  void ApplyRoundedRectClipsTo(gfxContext* aContext, int32_t A2DPRInt32,
                               uint32_t aBegin, uint32_t aEnd) const;

  // Draw (fill) the rounded rects in this clip to aContext
  void FillIntersectionOfRoundedRectClips(gfxContext* aContext,
                                          const Color& aColor,
                                          int32_t aAppUnitsPerDevPixel,
                                          uint32_t aBegin,
                                          uint32_t aEnd) const;
  // 'Draw' (create as a path, does not stroke or fill) aRoundRect to aContext
  already_AddRefed<Path> MakeRoundedRectPath(DrawTarget& aDrawTarget,
                                                  int32_t A2D,
                                                  const RoundedRect &aRoundRect) const;

  // Returns true if the intersection of aRect and this clip region is
  // non-empty. This is precise for DisplayItemClips with at most one
  // rounded rectangle. When multiple rounded rectangles are present, we just
  // check that the rectangle intersects all of them (but possibly in different
  // places). So it may return true when the correct answer is false.
  bool MayIntersect(const nsRect& aRect) const;

  // Return a rectangle contained in the intersection of aRect with this
  // clip region. Tries to return the largest possible rectangle, but may
  // not succeed.
  nsRect ApproximateIntersectInward(const nsRect& aRect) const;

  /*
   * Computes a region which contains the clipped area of this DisplayItemClip,
   * or if aOldClip is non-null, the union of the clipped area of this
   * DisplayItemClip with the clipped area of aOldClip translated by aShift.
   * The result is stored in aCombined. If the result would be infinite
   * (because one or both of the clips does no clipping), returns false.
   */
  bool ComputeRegionInClips(DisplayItemClip* aOldClip,
                            const nsPoint& aShift,
                            nsRegion* aCombined) const;

  // Returns false if aRect is definitely not clipped by a rounded corner in
  // this clip. Returns true if aRect is clipped by a rounded corner in this
  // clip or it can not be quickly determined that it is not clipped by a
  // rounded corner in this clip.
  bool IsRectClippedByRoundedCorner(const nsRect& aRect) const;

  // Returns false if aRect is definitely not clipped by anything in this clip.
  // Fast but not necessarily accurate.
  bool IsRectAffectedByClip(const nsRect& aRect) const;
  bool IsRectAffectedByClip(const nsIntRect& aRect, float aXScale, float aYScale, int32_t A2D) const;

  // Intersection of all rects in this clip ignoring any rounded corners.
  nsRect NonRoundedIntersection() const;

  // Intersect the given rects with all rects in this clip, ignoring any
  // rounded corners.
  nsRect ApplyNonRoundedIntersection(const nsRect& aRect) const;

  // Gets rid of any rounded corners in this clip.
  void RemoveRoundedCorners();

  // Adds the difference between Intersect(*this + aPoint, aBounds) and
  // Intersect(aOther, aOtherBounds) to aDifference (or a bounding-box thereof).
  void AddOffsetAndComputeDifference(uint32_t aStart, const nsPoint& aPoint, const nsRect& aBounds,
                                     const DisplayItemClip& aOther, uint32_t aOtherStart, const nsRect& aOtherBounds,
                                     nsRegion* aDifference);

  bool operator==(const DisplayItemClip& aOther) const {
    return mHaveClipRect == aOther.mHaveClipRect &&
           (!mHaveClipRect || mClipRect.IsEqualInterior(aOther.mClipRect)) &&
           mRoundedClipRects == aOther.mRoundedClipRects;
  }
  bool operator!=(const DisplayItemClip& aOther) const {
    return !(*this == aOther);
  }

  bool HasClip() const { return mHaveClipRect; }
  const nsRect& GetClipRect() const
  {
    NS_ASSERTION(HasClip(), "No clip rect!");
    return mClipRect;
  }

  void MoveBy(nsPoint aPoint);

  nsCString ToString() const;

  /**
   * Find the largest N such that the first N rounded rects in 'this' are
   * equal to the first N rounded rects in aOther, and N <= aMax.
   */
  uint32_t GetCommonRoundedRectCount(const DisplayItemClip& aOther,
                                     uint32_t aMax) const;
  uint32_t GetRoundedRectCount() const { return mRoundedClipRects.Length(); }
  void AppendRoundedRects(nsTArray<RoundedRect>* aArray, uint32_t aCount) const;

  static const DisplayItemClip& NoClip();

  static void Shutdown();

private:
  nsRect mClipRect;
  nsTArray<RoundedRect> mRoundedClipRects;
  // If mHaveClipRect is false then this object represents no clipping at all
  // and mRoundedClipRects must be empty.
  bool mHaveClipRect;
};

} // namespace mozilla

#endif /* DISPLAYITEMCLIP_H_ */