xref: /aosp_15_r20/external/skia/src/gpu/ganesh/GrClip.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2010 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef GrClip_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define GrClip_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRRect.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrAppliedClip.h"
16*c8dee2aaSAndroid Build Coastguard Worker 
17*c8dee2aaSAndroid Build Coastguard Worker class GrDrawOp;
18*c8dee2aaSAndroid Build Coastguard Worker class GrRecordingContext;
19*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu {
20*c8dee2aaSAndroid Build Coastguard Worker namespace ganesh {
21*c8dee2aaSAndroid Build Coastguard Worker class SurfaceDrawContext;
22*c8dee2aaSAndroid Build Coastguard Worker }
23*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skgpu
24*c8dee2aaSAndroid Build Coastguard Worker 
25*c8dee2aaSAndroid Build Coastguard Worker /**
26*c8dee2aaSAndroid Build Coastguard Worker  * GrClip is an abstract base class for applying a clip. It constructs a clip mask if necessary, and
27*c8dee2aaSAndroid Build Coastguard Worker  * fills out a GrAppliedClip instructing the caller on how to set up the draw state.
28*c8dee2aaSAndroid Build Coastguard Worker  */
29*c8dee2aaSAndroid Build Coastguard Worker class GrClip {
30*c8dee2aaSAndroid Build Coastguard Worker public:
31*c8dee2aaSAndroid Build Coastguard Worker     enum class Effect {
32*c8dee2aaSAndroid Build Coastguard Worker         // The clip conservatively modifies the draw's coverage but doesn't eliminate the draw
33*c8dee2aaSAndroid Build Coastguard Worker         kClipped,
34*c8dee2aaSAndroid Build Coastguard Worker         // The clip definitely does not modify the draw's coverage and the draw can be performed
35*c8dee2aaSAndroid Build Coastguard Worker         // without clipping (beyond the automatic device bounds clip).
36*c8dee2aaSAndroid Build Coastguard Worker         kUnclipped,
37*c8dee2aaSAndroid Build Coastguard Worker         // The clip definitely eliminates all of the draw's coverage and the draw can be skipped
38*c8dee2aaSAndroid Build Coastguard Worker         kClippedOut
39*c8dee2aaSAndroid Build Coastguard Worker     };
40*c8dee2aaSAndroid Build Coastguard Worker 
41*c8dee2aaSAndroid Build Coastguard Worker     struct PreClipResult {
42*c8dee2aaSAndroid Build Coastguard Worker         Effect  fEffect;
43*c8dee2aaSAndroid Build Coastguard Worker         SkRRect fRRect; // Ignore if 'isRRect' is false
44*c8dee2aaSAndroid Build Coastguard Worker         GrAA    fAA;    // Ignore if 'isRRect' is false
45*c8dee2aaSAndroid Build Coastguard Worker         bool    fIsRRect;
46*c8dee2aaSAndroid Build Coastguard Worker 
PreClipResultPreClipResult47*c8dee2aaSAndroid Build Coastguard Worker         PreClipResult(Effect effect) : fEffect(effect), fIsRRect(false) {}
PreClipResultPreClipResult48*c8dee2aaSAndroid Build Coastguard Worker         PreClipResult(SkRect rect, GrAA aa) : PreClipResult(SkRRect::MakeRect(rect), aa) {}
PreClipResultPreClipResult49*c8dee2aaSAndroid Build Coastguard Worker         PreClipResult(SkRRect rrect, GrAA aa)
50*c8dee2aaSAndroid Build Coastguard Worker                 : fEffect(Effect::kClipped)
51*c8dee2aaSAndroid Build Coastguard Worker                 , fRRect(rrect)
52*c8dee2aaSAndroid Build Coastguard Worker                 , fAA(aa)
53*c8dee2aaSAndroid Build Coastguard Worker                 , fIsRRect(true) {}
54*c8dee2aaSAndroid Build Coastguard Worker     };
55*c8dee2aaSAndroid Build Coastguard Worker 
~GrClip()56*c8dee2aaSAndroid Build Coastguard Worker     virtual ~GrClip() {}
57*c8dee2aaSAndroid Build Coastguard Worker 
58*c8dee2aaSAndroid Build Coastguard Worker     /**
59*c8dee2aaSAndroid Build Coastguard Worker      * Compute a conservative pixel bounds restricted to the given render target dimensions.
60*c8dee2aaSAndroid Build Coastguard Worker      * The returned bounds represent the limits of pixels that can be drawn; anything outside of the
61*c8dee2aaSAndroid Build Coastguard Worker      * bounds will be entirely clipped out.
62*c8dee2aaSAndroid Build Coastguard Worker      */
63*c8dee2aaSAndroid Build Coastguard Worker     virtual SkIRect getConservativeBounds() const = 0;
64*c8dee2aaSAndroid Build Coastguard Worker 
65*c8dee2aaSAndroid Build Coastguard Worker     /**
66*c8dee2aaSAndroid Build Coastguard Worker      * This computes a GrAppliedClip from the clip which in turn can be used to build a GrPipeline.
67*c8dee2aaSAndroid Build Coastguard Worker      * To determine the appropriate clipping implementation the GrClip subclass must know whether
68*c8dee2aaSAndroid Build Coastguard Worker      * the draw will enable HW AA or uses the stencil buffer. On input 'bounds' is a conservative
69*c8dee2aaSAndroid Build Coastguard Worker      * bounds of the draw that is to be clipped. If kClipped or kUnclipped is returned, the 'bounds'
70*c8dee2aaSAndroid Build Coastguard Worker      * will have been updated to be contained within the clip bounds (or the device's, for wide-open
71*c8dee2aaSAndroid Build Coastguard Worker      * clips). If kNoDraw is returned, 'bounds' and the applied clip are in an undetermined state
72*c8dee2aaSAndroid Build Coastguard Worker      * and should be ignored (and the draw should be skipped).
73*c8dee2aaSAndroid Build Coastguard Worker      */
74*c8dee2aaSAndroid Build Coastguard Worker     virtual Effect apply(GrRecordingContext*,
75*c8dee2aaSAndroid Build Coastguard Worker                          skgpu::ganesh::SurfaceDrawContext*,
76*c8dee2aaSAndroid Build Coastguard Worker                          GrDrawOp*,
77*c8dee2aaSAndroid Build Coastguard Worker                          GrAAType,
78*c8dee2aaSAndroid Build Coastguard Worker                          GrAppliedClip*,
79*c8dee2aaSAndroid Build Coastguard Worker                          SkRect* bounds) const = 0;
80*c8dee2aaSAndroid Build Coastguard Worker 
81*c8dee2aaSAndroid Build Coastguard Worker     /**
82*c8dee2aaSAndroid Build Coastguard Worker      * Perform preliminary, conservative analysis on the draw bounds as if it were provided to
83*c8dee2aaSAndroid Build Coastguard Worker      * apply(). The results of this are returned the PreClipResults struct, where 'result.fEffect'
84*c8dee2aaSAndroid Build Coastguard Worker      * corresponds to what 'apply' would return. If this value is kUnclipped or kNoDraw, then it
85*c8dee2aaSAndroid Build Coastguard Worker      * can be assumed that apply() would also always result in the same Effect.
86*c8dee2aaSAndroid Build Coastguard Worker      *
87*c8dee2aaSAndroid Build Coastguard Worker      * If kClipped is returned, apply() may further refine the effect to kUnclipped or kNoDraw,
88*c8dee2aaSAndroid Build Coastguard Worker      * with one exception. When 'result.fIsRRect' is true, preApply() reports the single round rect
89*c8dee2aaSAndroid Build Coastguard Worker      * and anti-aliased state that would act as an intersection on the draw geometry. If no further
90*c8dee2aaSAndroid Build Coastguard Worker      * action is taken to modify the draw, apply() will represent this round rect in the applied
91*c8dee2aaSAndroid Build Coastguard Worker      * clip.
92*c8dee2aaSAndroid Build Coastguard Worker      *
93*c8dee2aaSAndroid Build Coastguard Worker      * When set, 'result.fRRect' will intersect with the render target bounds but may extend
94*c8dee2aaSAndroid Build Coastguard Worker      * beyond it. If the render target bounds are the only clip effect on the draw, this is reported
95*c8dee2aaSAndroid Build Coastguard Worker      * as kUnclipped and not as a degenerate rrect that matches the bounds.
96*c8dee2aaSAndroid Build Coastguard Worker      */
preApply(const SkRect & drawBounds,GrAA aa)97*c8dee2aaSAndroid Build Coastguard Worker     virtual PreClipResult preApply(const SkRect& drawBounds, GrAA aa) const {
98*c8dee2aaSAndroid Build Coastguard Worker         SkIRect pixelBounds = GetPixelIBounds(drawBounds, aa);
99*c8dee2aaSAndroid Build Coastguard Worker         bool outside = !SkIRect::Intersects(pixelBounds, this->getConservativeBounds());
100*c8dee2aaSAndroid Build Coastguard Worker         return outside ? Effect::kClippedOut : Effect::kClipped;
101*c8dee2aaSAndroid Build Coastguard Worker     }
102*c8dee2aaSAndroid Build Coastguard Worker 
103*c8dee2aaSAndroid Build Coastguard Worker     /**
104*c8dee2aaSAndroid Build Coastguard Worker      * This is the maximum distance that a draw may extend beyond a clip's boundary and still count
105*c8dee2aaSAndroid Build Coastguard Worker      * count as "on the other side". We leave some slack because floating point rounding error is
106*c8dee2aaSAndroid Build Coastguard Worker      * likely to blame. The rationale for 1e-3 is that in the coverage case (and barring unexpected
107*c8dee2aaSAndroid Build Coastguard Worker      * rounding), as long as coverage stays within 0.5 * 1/256 of its intended value it shouldn't
108*c8dee2aaSAndroid Build Coastguard Worker      * have any effect on the final pixel values.
109*c8dee2aaSAndroid Build Coastguard Worker      */
110*c8dee2aaSAndroid Build Coastguard Worker     constexpr static SkScalar kBoundsTolerance = 1e-3f;
111*c8dee2aaSAndroid Build Coastguard Worker 
112*c8dee2aaSAndroid Build Coastguard Worker     /**
113*c8dee2aaSAndroid Build Coastguard Worker      * This is the slack around a half-pixel vertex coordinate where we don't trust the GPU's
114*c8dee2aaSAndroid Build Coastguard Worker      * rasterizer to round consistently. The rounding method is not defined in GPU specs, and
115*c8dee2aaSAndroid Build Coastguard Worker      * rasterizer precision frequently introduces errors where a fraction < 1/2 still rounds up.
116*c8dee2aaSAndroid Build Coastguard Worker      *
117*c8dee2aaSAndroid Build Coastguard Worker      * For non-AA bounds edges, an edge value between 0.45 and 0.55 will round in or round out
118*c8dee2aaSAndroid Build Coastguard Worker      * depending on what side its on. Outside of this range, the non-AA edge will snap using round()
119*c8dee2aaSAndroid Build Coastguard Worker      */
120*c8dee2aaSAndroid Build Coastguard Worker     constexpr static SkScalar kHalfPixelRoundingTolerance = 5e-2f;
121*c8dee2aaSAndroid Build Coastguard Worker 
122*c8dee2aaSAndroid Build Coastguard Worker     /**
123*c8dee2aaSAndroid Build Coastguard Worker      * Returns true if the given draw bounds count as entirely inside the clip.
124*c8dee2aaSAndroid Build Coastguard Worker 
125*c8dee2aaSAndroid Build Coastguard Worker      * @param innerClipBounds   device-space rect fully contained by the clip
126*c8dee2aaSAndroid Build Coastguard Worker      * @param drawBounds        device-space bounds of the query region.
127*c8dee2aaSAndroid Build Coastguard Worker      */
IsInsideClip(const SkIRect & innerClipBounds,const SkRect & drawBounds,GrAA aa)128*c8dee2aaSAndroid Build Coastguard Worker     static bool IsInsideClip(const SkIRect& innerClipBounds, const SkRect& drawBounds, GrAA aa) {
129*c8dee2aaSAndroid Build Coastguard Worker         return innerClipBounds.contains(GetPixelIBounds(drawBounds, aa));
130*c8dee2aaSAndroid Build Coastguard Worker     }
131*c8dee2aaSAndroid Build Coastguard Worker 
132*c8dee2aaSAndroid Build Coastguard Worker     /**
133*c8dee2aaSAndroid Build Coastguard Worker      * Returns true if the given draw bounds count as entirely outside the clip.
134*c8dee2aaSAndroid Build Coastguard Worker 
135*c8dee2aaSAndroid Build Coastguard Worker      * @param outerClipBounds   device-space rect that contains the clip
136*c8dee2aaSAndroid Build Coastguard Worker      * @param drawBounds        device-space bounds of the query region.
137*c8dee2aaSAndroid Build Coastguard Worker      * @param aa                whether or not the draw will use anti-aliasing
138*c8dee2aaSAndroid Build Coastguard Worker      */
IsOutsideClip(const SkIRect & outerClipBounds,const SkRect & drawBounds,GrAA aa)139*c8dee2aaSAndroid Build Coastguard Worker     static bool IsOutsideClip(const SkIRect& outerClipBounds, const SkRect& drawBounds, GrAA aa) {
140*c8dee2aaSAndroid Build Coastguard Worker         return !SkIRect::Intersects(outerClipBounds, GetPixelIBounds(drawBounds, aa));
141*c8dee2aaSAndroid Build Coastguard Worker     }
142*c8dee2aaSAndroid Build Coastguard Worker 
143*c8dee2aaSAndroid Build Coastguard Worker     // Modifies the behavior of GetPixelIBounds
144*c8dee2aaSAndroid Build Coastguard Worker     enum class BoundsType {
145*c8dee2aaSAndroid Build Coastguard Worker         /**
146*c8dee2aaSAndroid Build Coastguard Worker          * Returns the tightest integer pixel bounding box such that the rasterization of a shape
147*c8dee2aaSAndroid Build Coastguard Worker          * contained in the analytic 'bounds', using the 'aa' method, will only have non-zero
148*c8dee2aaSAndroid Build Coastguard Worker          * coverage for pixels inside the returned bounds. Pixels outside the bounds will either
149*c8dee2aaSAndroid Build Coastguard Worker          * not be touched, or will have 0 coverage that creates no visual change.
150*c8dee2aaSAndroid Build Coastguard Worker          */
151*c8dee2aaSAndroid Build Coastguard Worker         kExterior,
152*c8dee2aaSAndroid Build Coastguard Worker         /**
153*c8dee2aaSAndroid Build Coastguard Worker          * Returns the largest integer pixel bounding box such that were 'bounds' to be rendered as
154*c8dee2aaSAndroid Build Coastguard Worker          * a solid fill using 'aa', every pixel in the returned bounds will have full coverage.
155*c8dee2aaSAndroid Build Coastguard Worker          *
156*c8dee2aaSAndroid Build Coastguard Worker          * This effectively determines the pixels that are definitely covered by a draw or clip. It
157*c8dee2aaSAndroid Build Coastguard Worker          * effectively performs the opposite operations as GetOuterPixelBounds. It rounds in instead
158*c8dee2aaSAndroid Build Coastguard Worker          * of out for coverage AA and non-AA near pixel centers.
159*c8dee2aaSAndroid Build Coastguard Worker          */
160*c8dee2aaSAndroid Build Coastguard Worker         kInterior
161*c8dee2aaSAndroid Build Coastguard Worker     };
162*c8dee2aaSAndroid Build Coastguard Worker 
163*c8dee2aaSAndroid Build Coastguard Worker     /**
164*c8dee2aaSAndroid Build Coastguard Worker      * Convert the analytic bounds of a shape into an integer pixel bounds, where the given aa type
165*c8dee2aaSAndroid Build Coastguard Worker      * is used when the shape is rendered. The bounds mode can be used to query exterior or interior
166*c8dee2aaSAndroid Build Coastguard Worker      * pixel boundaries. Interior bounds only make sense when its know that the analytic bounds
167*c8dee2aaSAndroid Build Coastguard Worker      * are filled completely.
168*c8dee2aaSAndroid Build Coastguard Worker      *
169*c8dee2aaSAndroid Build Coastguard Worker      * NOTE: When using kExterior_Bounds, some coverage-AA rendering methods may still touch a pixel
170*c8dee2aaSAndroid Build Coastguard Worker      * center outside of these bounds but will evaluate to 0 coverage. This is visually acceptable,
171*c8dee2aaSAndroid Build Coastguard Worker      * but an additional outset of 1px should be used for dst proxy access.
172*c8dee2aaSAndroid Build Coastguard Worker      */
173*c8dee2aaSAndroid Build Coastguard Worker     static SkIRect GetPixelIBounds(const SkRect& bounds, GrAA aa,
174*c8dee2aaSAndroid Build Coastguard Worker                                    BoundsType mode = BoundsType::kExterior) {
175*c8dee2aaSAndroid Build Coastguard Worker         auto roundLow = [aa](float v) {
176*c8dee2aaSAndroid Build Coastguard Worker             v += kBoundsTolerance;
177*c8dee2aaSAndroid Build Coastguard Worker             return aa == GrAA::kNo ? SkScalarRoundToInt(v - kHalfPixelRoundingTolerance)
178*c8dee2aaSAndroid Build Coastguard Worker                                    : SkScalarFloorToInt(v);
179*c8dee2aaSAndroid Build Coastguard Worker         };
180*c8dee2aaSAndroid Build Coastguard Worker         auto roundHigh = [aa](float v) {
181*c8dee2aaSAndroid Build Coastguard Worker             v -= kBoundsTolerance;
182*c8dee2aaSAndroid Build Coastguard Worker             return aa == GrAA::kNo ? SkScalarRoundToInt(v + kHalfPixelRoundingTolerance)
183*c8dee2aaSAndroid Build Coastguard Worker                                    : SkScalarCeilToInt(v);
184*c8dee2aaSAndroid Build Coastguard Worker         };
185*c8dee2aaSAndroid Build Coastguard Worker 
186*c8dee2aaSAndroid Build Coastguard Worker         if (bounds.isEmpty()) {
187*c8dee2aaSAndroid Build Coastguard Worker             return SkIRect::MakeEmpty();
188*c8dee2aaSAndroid Build Coastguard Worker         }
189*c8dee2aaSAndroid Build Coastguard Worker 
190*c8dee2aaSAndroid Build Coastguard Worker         if (mode == BoundsType::kExterior) {
191*c8dee2aaSAndroid Build Coastguard Worker             return SkIRect::MakeLTRB(roundLow(bounds.fLeft),   roundLow(bounds.fTop),
192*c8dee2aaSAndroid Build Coastguard Worker                                      roundHigh(bounds.fRight), roundHigh(bounds.fBottom));
193*c8dee2aaSAndroid Build Coastguard Worker         } else {
194*c8dee2aaSAndroid Build Coastguard Worker             return SkIRect::MakeLTRB(roundHigh(bounds.fLeft), roundHigh(bounds.fTop),
195*c8dee2aaSAndroid Build Coastguard Worker                                      roundLow(bounds.fRight), roundLow(bounds.fBottom));
196*c8dee2aaSAndroid Build Coastguard Worker         }
197*c8dee2aaSAndroid Build Coastguard Worker     }
198*c8dee2aaSAndroid Build Coastguard Worker 
199*c8dee2aaSAndroid Build Coastguard Worker     /**
200*c8dee2aaSAndroid Build Coastguard Worker      * Returns true if the given rect counts as aligned with pixel boundaries.
201*c8dee2aaSAndroid Build Coastguard Worker      */
IsPixelAligned(const SkRect & rect)202*c8dee2aaSAndroid Build Coastguard Worker     static bool IsPixelAligned(const SkRect& rect) {
203*c8dee2aaSAndroid Build Coastguard Worker         return SkScalarAbs(SkScalarRoundToScalar(rect.fLeft) - rect.fLeft) <= kBoundsTolerance &&
204*c8dee2aaSAndroid Build Coastguard Worker                SkScalarAbs(SkScalarRoundToScalar(rect.fTop) - rect.fTop) <= kBoundsTolerance &&
205*c8dee2aaSAndroid Build Coastguard Worker                SkScalarAbs(SkScalarRoundToScalar(rect.fRight) - rect.fRight) <= kBoundsTolerance &&
206*c8dee2aaSAndroid Build Coastguard Worker                SkScalarAbs(SkScalarRoundToScalar(rect.fBottom) - rect.fBottom) <= kBoundsTolerance;
207*c8dee2aaSAndroid Build Coastguard Worker     }
208*c8dee2aaSAndroid Build Coastguard Worker };
209*c8dee2aaSAndroid Build Coastguard Worker 
210*c8dee2aaSAndroid Build Coastguard Worker 
211*c8dee2aaSAndroid Build Coastguard Worker /**
212*c8dee2aaSAndroid Build Coastguard Worker  * GrHardClip never uses coverage FPs. It can only enforce the clip using the already-existing
213*c8dee2aaSAndroid Build Coastguard Worker  * stencil buffer contents and/or fixed-function state like scissor. Always aliased if MSAA is off.
214*c8dee2aaSAndroid Build Coastguard Worker  */
215*c8dee2aaSAndroid Build Coastguard Worker class GrHardClip : public GrClip {
216*c8dee2aaSAndroid Build Coastguard Worker public:
217*c8dee2aaSAndroid Build Coastguard Worker     /**
218*c8dee2aaSAndroid Build Coastguard Worker      * Sets the appropriate hardware state modifications on GrAppliedHardClip that will implement
219*c8dee2aaSAndroid Build Coastguard Worker      * the clip. On input 'bounds' is a conservative bounds of the draw that is to be clipped. After
220*c8dee2aaSAndroid Build Coastguard Worker      * return 'bounds' has been intersected with a conservative bounds of the clip.
221*c8dee2aaSAndroid Build Coastguard Worker      */
222*c8dee2aaSAndroid Build Coastguard Worker     virtual Effect apply(GrAppliedHardClip* out, SkIRect* bounds) const = 0;
223*c8dee2aaSAndroid Build Coastguard Worker 
224*c8dee2aaSAndroid Build Coastguard Worker private:
apply(GrRecordingContext *,skgpu::ganesh::SurfaceDrawContext *,GrDrawOp *,GrAAType aa,GrAppliedClip * out,SkRect * bounds)225*c8dee2aaSAndroid Build Coastguard Worker     Effect apply(GrRecordingContext*,
226*c8dee2aaSAndroid Build Coastguard Worker                  skgpu::ganesh::SurfaceDrawContext*,
227*c8dee2aaSAndroid Build Coastguard Worker                  GrDrawOp*,
228*c8dee2aaSAndroid Build Coastguard Worker                  GrAAType aa,
229*c8dee2aaSAndroid Build Coastguard Worker                  GrAppliedClip* out,
230*c8dee2aaSAndroid Build Coastguard Worker                  SkRect* bounds) const final {
231*c8dee2aaSAndroid Build Coastguard Worker         SkIRect pixelBounds = GetPixelIBounds(*bounds, GrAA(aa != GrAAType::kNone));
232*c8dee2aaSAndroid Build Coastguard Worker         Effect effect = this->apply(&out->hardClip(), &pixelBounds);
233*c8dee2aaSAndroid Build Coastguard Worker         bounds->intersect(SkRect::Make(pixelBounds));
234*c8dee2aaSAndroid Build Coastguard Worker         return effect;
235*c8dee2aaSAndroid Build Coastguard Worker     }
236*c8dee2aaSAndroid Build Coastguard Worker };
237*c8dee2aaSAndroid Build Coastguard Worker 
238*c8dee2aaSAndroid Build Coastguard Worker #endif
239