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