1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/base/DisplayItemClip.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,175 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef DISPLAYITEMCLIP_H_ 1.10 +#define DISPLAYITEMCLIP_H_ 1.11 + 1.12 +#include "nsRect.h" 1.13 +#include "nsTArray.h" 1.14 +#include "nsStyleConsts.h" 1.15 + 1.16 +class gfxContext; 1.17 +class nsDisplayItem; 1.18 +class nsPresContext; 1.19 +class nsRegion; 1.20 + 1.21 +namespace mozilla { 1.22 + 1.23 +/** 1.24 + * An DisplayItemClip represents the intersection of an optional rectangle 1.25 + * with a list of rounded rectangles (which is often empty), all in appunits. 1.26 + * It can represent everything CSS clipping can do to an element (except for 1.27 + * SVG clip-path), including no clipping at all. 1.28 + */ 1.29 +class DisplayItemClip { 1.30 +public: 1.31 + struct RoundedRect { 1.32 + nsRect mRect; 1.33 + // Indices into mRadii are the NS_CORNER_* constants in nsStyleConsts.h 1.34 + nscoord mRadii[8]; 1.35 + 1.36 + RoundedRect operator+(const nsPoint& aOffset) const { 1.37 + RoundedRect r = *this; 1.38 + r.mRect += aOffset; 1.39 + return r; 1.40 + } 1.41 + bool operator==(const RoundedRect& aOther) const { 1.42 + if (!mRect.IsEqualInterior(aOther.mRect)) { 1.43 + return false; 1.44 + } 1.45 + 1.46 + NS_FOR_CSS_HALF_CORNERS(corner) { 1.47 + if (mRadii[corner] != aOther.mRadii[corner]) { 1.48 + return false; 1.49 + } 1.50 + } 1.51 + return true; 1.52 + } 1.53 + bool operator!=(const RoundedRect& aOther) const { 1.54 + return !(*this == aOther); 1.55 + } 1.56 + }; 1.57 + 1.58 + // Constructs a DisplayItemClip that does no clipping at all. 1.59 + DisplayItemClip() : mHaveClipRect(false) {} 1.60 + 1.61 + void SetTo(const nsRect& aRect); 1.62 + void SetTo(const nsRect& aRect, const nscoord* aRadii); 1.63 + void IntersectWith(const DisplayItemClip& aOther); 1.64 + 1.65 + // Apply this |DisplayItemClip| to the given gfxContext. Any saving of state 1.66 + // or clearing of other clips must be done by the caller. 1.67 + // See aBegin/aEnd note on ApplyRoundedRectsTo. 1.68 + void ApplyTo(gfxContext* aContext, nsPresContext* aPresContext, 1.69 + uint32_t aBegin = 0, uint32_t aEnd = UINT32_MAX); 1.70 + 1.71 + void ApplyRectTo(gfxContext* aContext, int32_t A2D) const; 1.72 + // Applies the rounded rects in this Clip to aContext 1.73 + // Will only apply rounded rects from aBegin (inclusive) to aEnd 1.74 + // (exclusive) or the number of rounded rects, whichever is smaller. 1.75 + void ApplyRoundedRectsTo(gfxContext* aContext, int32_t A2DPRInt32, 1.76 + uint32_t aBegin, uint32_t aEnd) const; 1.77 + 1.78 + // Draw (fill) the rounded rects in this clip to aContext 1.79 + void DrawRoundedRectsTo(gfxContext* aContext, int32_t A2D, 1.80 + uint32_t aBegin, uint32_t aEnd) const; 1.81 + // 'Draw' (create as a path, does not stroke or fill) aRoundRect to aContext 1.82 + void AddRoundedRectPathTo(gfxContext* aContext, int32_t A2D, 1.83 + const RoundedRect &aRoundRect) const; 1.84 + 1.85 + // Returns true if the intersection of aRect and this clip region is 1.86 + // non-empty. This is precise for DisplayItemClips with at most one 1.87 + // rounded rectangle. When multiple rounded rectangles are present, we just 1.88 + // check that the rectangle intersects all of them (but possibly in different 1.89 + // places). So it may return true when the correct answer is false. 1.90 + bool MayIntersect(const nsRect& aRect) const; 1.91 + // Return a rectangle contained in the intersection of aRect with this 1.92 + // clip region. Tries to return the largest possible rectangle, but may 1.93 + // not succeed. 1.94 + nsRect ApproximateIntersectInward(const nsRect& aRect) const; 1.95 + 1.96 + /* 1.97 + * Computes a region which contains the clipped area of this DisplayItemClip, 1.98 + * or if aOldClip is non-null, the union of the clipped area of this 1.99 + * DisplayItemClip with the clipped area of aOldClip translated by aShift. 1.100 + * The result is stored in aCombined. If the result would be infinite 1.101 + * (because one or both of the clips does no clipping), returns false. 1.102 + */ 1.103 + bool ComputeRegionInClips(DisplayItemClip* aOldClip, 1.104 + const nsPoint& aShift, 1.105 + nsRegion* aCombined) const; 1.106 + 1.107 + // Returns false if aRect is definitely not clipped by a rounded corner in 1.108 + // this clip. Returns true if aRect is clipped by a rounded corner in this 1.109 + // clip or it can not be quickly determined that it is not clipped by a 1.110 + // rounded corner in this clip. 1.111 + bool IsRectClippedByRoundedCorner(const nsRect& aRect) const; 1.112 + 1.113 + // Returns false if aRect is definitely not clipped by anything in this clip. 1.114 + // Fast but not necessarily accurate. 1.115 + bool IsRectAffectedByClip(const nsRect& aRect) const; 1.116 + 1.117 + // Intersection of all rects in this clip ignoring any rounded corners. 1.118 + nsRect NonRoundedIntersection() const; 1.119 + 1.120 + // Intersect the given rects with all rects in this clip, ignoring any 1.121 + // rounded corners. 1.122 + nsRect ApplyNonRoundedIntersection(const nsRect& aRect) const; 1.123 + 1.124 + // Gets rid of any rounded corners in this clip. 1.125 + void RemoveRoundedCorners(); 1.126 + 1.127 + // Adds the difference between Intersect(*this + aPoint, aBounds) and 1.128 + // Intersect(aOther, aOtherBounds) to aDifference (or a bounding-box thereof). 1.129 + void AddOffsetAndComputeDifference(const nsPoint& aPoint, const nsRect& aBounds, 1.130 + const DisplayItemClip& aOther, const nsRect& aOtherBounds, 1.131 + nsRegion* aDifference); 1.132 + 1.133 + bool operator==(const DisplayItemClip& aOther) const { 1.134 + return mHaveClipRect == aOther.mHaveClipRect && 1.135 + (!mHaveClipRect || mClipRect.IsEqualInterior(aOther.mClipRect)) && 1.136 + mRoundedClipRects == aOther.mRoundedClipRects; 1.137 + } 1.138 + bool operator!=(const DisplayItemClip& aOther) const { 1.139 + return !(*this == aOther); 1.140 + } 1.141 + 1.142 + bool HasClip() const { return mHaveClipRect; } 1.143 + const nsRect& GetClipRect() const 1.144 + { 1.145 + NS_ASSERTION(HasClip(), "No clip rect!"); 1.146 + return mClipRect; 1.147 + } 1.148 + 1.149 + void MoveBy(nsPoint aPoint); 1.150 + 1.151 +#ifdef MOZ_DUMP_PAINTING 1.152 + nsCString ToString() const; 1.153 +#endif 1.154 + 1.155 + /** 1.156 + * Find the largest N such that the first N rounded rects in 'this' are 1.157 + * equal to the first N rounded rects in aOther, and N <= aMax. 1.158 + */ 1.159 + uint32_t GetCommonRoundedRectCount(const DisplayItemClip& aOther, 1.160 + uint32_t aMax) const; 1.161 + uint32_t GetRoundedRectCount() const { return mRoundedClipRects.Length(); } 1.162 + void AppendRoundedRects(nsTArray<RoundedRect>* aArray, uint32_t aCount) const; 1.163 + 1.164 + static const DisplayItemClip& NoClip(); 1.165 + 1.166 + static void Shutdown(); 1.167 + 1.168 +private: 1.169 + nsRect mClipRect; 1.170 + nsTArray<RoundedRect> mRoundedClipRects; 1.171 + // If mHaveClipRect is false then this object represents no clipping at all 1.172 + // and mRoundedClipRects must be empty. 1.173 + bool mHaveClipRect; 1.174 +}; 1.175 + 1.176 +} 1.177 + 1.178 +#endif /* DISPLAYITEMCLIP_H_ */