DisplayItemClip.h (7188B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef DISPLAYITEMCLIP_H_ 8 #define DISPLAYITEMCLIP_H_ 9 10 #include "mozilla/AlreadyAddRefed.h" 11 #include "nsRect.h" 12 #include "nsTArray.h" 13 14 class gfxContext; 15 class nsPresContext; 16 class nsRegion; 17 18 namespace mozilla { 19 namespace gfx { 20 class DrawTarget; 21 class Path; 22 } // namespace gfx 23 namespace layers { 24 class StackingContextHelper; 25 } // namespace layers 26 namespace wr { 27 struct ComplexClipRegion; 28 } // namespace wr 29 } // namespace mozilla 30 31 namespace mozilla { 32 33 /** 34 * An DisplayItemClip represents the intersection of an optional rectangle 35 * with a list of rounded rectangles (which is often empty), all in appunits. 36 * It can represent everything CSS clipping can do to an element (except for 37 * SVG clip-path), including no clipping at all. 38 */ 39 class DisplayItemClip { 40 typedef mozilla::gfx::DeviceColor DeviceColor; 41 typedef mozilla::gfx::DrawTarget DrawTarget; 42 typedef mozilla::gfx::Path Path; 43 44 public: 45 struct RoundedRect { 46 nsRect mRect; 47 // Indices into mRadii are the HalfCorner values in gfx/2d/Types.h 48 nsRectCornerRadii mRadii; 49 50 RoundedRect operator+(const nsPoint& aOffset) const { 51 RoundedRect r = *this; 52 r.mRect += aOffset; 53 return r; 54 } 55 bool operator==(const RoundedRect& aOther) const { 56 if (!mRect.IsEqualInterior(aOther.mRect)) { 57 return false; 58 } 59 if (mRadii != aOther.mRadii) { 60 return false; 61 } 62 return true; 63 } 64 bool operator!=(const RoundedRect& aOther) const { 65 return !(*this == aOther); 66 } 67 }; 68 69 // Constructs a DisplayItemClip that does no clipping at all. 70 DisplayItemClip() : mHaveClipRect(false) {} 71 72 void SetTo(const nsRect& aRect); 73 void SetTo(const nsRect& aRect, const nsRectCornerRadii* aRadii); 74 void SetTo(const nsRect& aRect, const nsRect& aRoundedRect, 75 const nsRectCornerRadii* aRadii); 76 void IntersectWith(const DisplayItemClip& aOther); 77 78 // Apply this |DisplayItemClip| to the given gfxContext. Any saving of state 79 // or clearing of other clips must be done by the caller. 80 // See aBegin/aEnd note on ApplyRoundedRectsTo. 81 void ApplyTo(gfxContext* aContext, int32_t A2D) const; 82 83 void ApplyRectTo(gfxContext* aContext, int32_t A2D) const; 84 // Applies the rounded rects in this Clip to aContext 85 // Will only apply rounded rects from aBegin (inclusive) to aEnd 86 // (exclusive) or the number of rounded rects, whichever is smaller. 87 void ApplyRoundedRectClipsTo(gfxContext* aContext, int32_t A2DPRInt32, 88 uint32_t aBegin, uint32_t aEnd) const; 89 90 // Draw (fill) the rounded rects in this clip to aContext 91 void FillIntersectionOfRoundedRectClips(gfxContext* aContext, 92 const DeviceColor& aColor, 93 int32_t aAppUnitsPerDevPixel) const; 94 // 'Draw' (create as a path, does not stroke or fill) aRoundRect to aContext 95 already_AddRefed<Path> MakeRoundedRectPath( 96 DrawTarget& aDrawTarget, int32_t A2D, 97 const RoundedRect& aRoundRect) const; 98 99 // Returns true if the intersection of aRect and this clip region is 100 // non-empty. This is precise for DisplayItemClips with at most one 101 // rounded rectangle. When multiple rounded rectangles are present, we just 102 // check that the rectangle intersects all of them (but possibly in different 103 // places). So it may return true when the correct answer is false. 104 bool MayIntersect(const nsRect& aRect) const; 105 106 // Return a rectangle contained in the intersection of aRect with this 107 // clip region. Tries to return the largest possible rectangle, but may 108 // not succeed. 109 nsRect ApproximateIntersectInward(const nsRect& aRect) const; 110 111 /* 112 * Computes a region which contains the clipped area of this DisplayItemClip, 113 * or if aOldClip is non-null, the union of the clipped area of this 114 * DisplayItemClip with the clipped area of aOldClip translated by aShift. 115 * The result is stored in aCombined. If the result would be infinite 116 * (because one or both of the clips does no clipping), returns false. 117 */ 118 bool ComputeRegionInClips(const DisplayItemClip* aOldClip, 119 const nsPoint& aShift, nsRegion* aCombined) const; 120 121 // Returns false if aRect is definitely not clipped by a rounded corner in 122 // this clip. Returns true if aRect is clipped by a rounded corner in this 123 // clip or it can not be quickly determined that it is not clipped by a 124 // rounded corner in this clip. 125 bool IsRectClippedByRoundedCorner(const nsRect& aRect) const; 126 127 // Returns false if aRect is definitely not clipped by anything in this clip. 128 // Fast but not necessarily accurate. 129 bool IsRectAffectedByClip(const nsRect& aRect) const; 130 bool IsRectAffectedByClip(const nsIntRect& aRect, float aXScale, 131 float aYScale, int32_t A2D) const; 132 133 // Intersection of all rects in this clip ignoring any rounded corners. 134 nsRect NonRoundedIntersection() const; 135 136 // Intersect the given rects with all rects in this clip, ignoring any 137 // rounded corners. 138 nsRect ApplyNonRoundedIntersection(const nsRect& aRect) const; 139 140 // Gets rid of any rounded corners in this clip. 141 void RemoveRoundedCorners(); 142 143 // Adds the difference between Intersect(*this + aPoint, aBounds) and 144 // Intersect(aOther, aOtherBounds) to aDifference (or a bounding-box thereof). 145 void AddOffsetAndComputeDifference(const nsPoint& aPoint, 146 const nsRect& aBounds, 147 const DisplayItemClip& aOther, 148 const nsRect& aOtherBounds, 149 nsRegion* aDifference); 150 151 bool operator==(const DisplayItemClip& aOther) const { 152 return mHaveClipRect == aOther.mHaveClipRect && 153 (!mHaveClipRect || mClipRect.IsEqualInterior(aOther.mClipRect)) && 154 mRoundedClipRects == aOther.mRoundedClipRects; 155 } 156 bool operator!=(const DisplayItemClip& aOther) const { 157 return !(*this == aOther); 158 } 159 160 bool HasClip() const { return mHaveClipRect; } 161 const nsRect& GetClipRect() const { 162 NS_ASSERTION(HasClip(), "No clip rect!"); 163 return mClipRect; 164 } 165 166 void MoveBy(const nsPoint& aPoint); 167 168 nsCString ToString() const; 169 170 uint32_t GetRoundedRectCount() const { return mRoundedClipRects.Length(); } 171 void AppendRoundedRects(nsTArray<RoundedRect>* aArray) const; 172 173 void ToComplexClipRegions(int32_t aAppUnitsPerDevPixel, 174 nsTArray<wr::ComplexClipRegion>& aOutArray) const; 175 176 static const DisplayItemClip& NoClip(); 177 178 static void Shutdown(); 179 180 private: 181 nsRect mClipRect; 182 CopyableTArray<RoundedRect> mRoundedClipRects; 183 // If mHaveClipRect is false then this object represents no clipping at all 184 // and mRoundedClipRects must be empty. 185 bool mHaveClipRect; 186 }; 187 188 } // namespace mozilla 189 190 #endif /* DISPLAYITEMCLIP_H_ */