Line data Source code
1 : /*
2 : * Copyright 2013 Google Inc.
3 : *
4 : * Use of this source code is governed by a BSD-style license that can be
5 : * found in the LICENSE file.
6 : */
7 :
8 : #include "SkBitmapDevice.h"
9 : #include "SkDraw.h"
10 : #include "SkImageFilter.h"
11 : #include "SkImageFilterCache.h"
12 : #include "SkMallocPixelRef.h"
13 : #include "SkMatrix.h"
14 : #include "SkPaint.h"
15 : #include "SkPath.h"
16 : #include "SkPixelRef.h"
17 : #include "SkPixmap.h"
18 : #include "SkRasterClip.h"
19 : #include "SkRasterHandleAllocator.h"
20 : #include "SkShader.h"
21 : #include "SkSpecialImage.h"
22 : #include "SkSurface.h"
23 : #include "SkVertices.h"
24 :
25 : class SkColorTable;
26 :
27 107 : static bool valid_for_bitmap_device(const SkImageInfo& info,
28 : SkAlphaType* newAlphaType) {
29 107 : if (info.width() < 0 || info.height() < 0) {
30 0 : return false;
31 : }
32 :
33 : // TODO: can we stop supporting kUnknown in SkBitmkapDevice?
34 107 : if (kUnknown_SkColorType == info.colorType()) {
35 0 : if (newAlphaType) {
36 0 : *newAlphaType = kUnknown_SkAlphaType;
37 : }
38 0 : return true;
39 : }
40 :
41 107 : switch (info.alphaType()) {
42 : case kPremul_SkAlphaType:
43 : case kOpaque_SkAlphaType:
44 107 : break;
45 : default:
46 0 : return false;
47 : }
48 :
49 107 : SkAlphaType canonicalAlphaType = info.alphaType();
50 :
51 107 : switch (info.colorType()) {
52 : case kAlpha_8_SkColorType:
53 4 : break;
54 : case kRGB_565_SkColorType:
55 0 : canonicalAlphaType = kOpaque_SkAlphaType;
56 0 : break;
57 : case kN32_SkColorType:
58 103 : break;
59 : case kRGBA_F16_SkColorType:
60 0 : break;
61 : default:
62 0 : return false;
63 : }
64 :
65 107 : if (newAlphaType) {
66 22 : *newAlphaType = canonicalAlphaType;
67 : }
68 107 : return true;
69 : }
70 :
71 0 : SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap)
72 0 : : INHERITED(bitmap.info(), SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType))
73 : , fBitmap(bitmap)
74 0 : , fRCStack(bitmap.width(), bitmap.height())
75 : {
76 0 : SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr));
77 0 : fBitmap.lockPixels();
78 0 : }
79 :
80 0 : SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& info) {
81 0 : return Create(info, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType));
82 : }
83 :
84 85 : SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps,
85 85 : SkRasterHandleAllocator::Handle hndl)
86 : : INHERITED(bitmap.info(), surfaceProps)
87 : , fBitmap(bitmap)
88 : , fRasterHandle(hndl)
89 85 : , fRCStack(bitmap.width(), bitmap.height())
90 : {
91 85 : SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr));
92 85 : fBitmap.lockPixels();
93 85 : }
94 :
95 22 : SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
96 : const SkSurfaceProps& surfaceProps,
97 : SkRasterHandleAllocator* allocator) {
98 22 : SkAlphaType newAT = origInfo.alphaType();
99 22 : if (!valid_for_bitmap_device(origInfo, &newAT)) {
100 0 : return nullptr;
101 : }
102 :
103 22 : SkRasterHandleAllocator::Handle hndl = nullptr;
104 44 : const SkImageInfo info = origInfo.makeAlphaType(newAT);
105 44 : SkBitmap bitmap;
106 :
107 22 : if (kUnknown_SkColorType == info.colorType()) {
108 0 : if (!bitmap.setInfo(info)) {
109 0 : return nullptr;
110 : }
111 22 : } else if (allocator) {
112 0 : hndl = allocator->allocBitmap(info, &bitmap);
113 0 : if (!hndl) {
114 0 : return nullptr;
115 : }
116 22 : } else if (info.isOpaque()) {
117 : // If this bitmap is opaque, we don't have any sensible default color,
118 : // so we just return uninitialized pixels.
119 3 : if (!bitmap.tryAllocPixels(info)) {
120 0 : return nullptr;
121 : }
122 : } else {
123 : // This bitmap has transparency, so we'll zero the pixels (to transparent).
124 : // We use the flag as a faster alloc-then-eraseColor(SK_ColorTRANSPARENT).
125 19 : if (!bitmap.tryAllocPixels(info, nullptr/*colortable*/, SkBitmap::kZeroPixels_AllocFlag)) {
126 0 : return nullptr;
127 : }
128 : }
129 :
130 22 : return new SkBitmapDevice(bitmap, surfaceProps, hndl);
131 : }
132 :
133 0 : void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
134 0 : SkASSERT(bm.width() == fBitmap.width());
135 0 : SkASSERT(bm.height() == fBitmap.height());
136 0 : fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config)
137 0 : fBitmap.lockPixels();
138 0 : this->privateResize(fBitmap.info().width(), fBitmap.info().height());
139 0 : }
140 :
141 22 : SkBaseDevice* SkBitmapDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
142 22 : const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry);
143 22 : return SkBitmapDevice::Create(cinfo.fInfo, surfaceProps, cinfo.fAllocator);
144 : }
145 :
146 473 : bool SkBitmapDevice::onAccessPixels(SkPixmap* pmap) {
147 473 : if (this->onPeekPixels(pmap)) {
148 473 : fBitmap.notifyPixelsChanged();
149 473 : return true;
150 : }
151 0 : return false;
152 : }
153 :
154 513 : bool SkBitmapDevice::onPeekPixels(SkPixmap* pmap) {
155 1026 : const SkImageInfo info = fBitmap.info();
156 513 : if (fBitmap.getPixels() && (kUnknown_SkColorType != info.colorType())) {
157 513 : SkColorTable* ctable = nullptr;
158 513 : pmap->reset(fBitmap.info(), fBitmap.getPixels(), fBitmap.rowBytes(), ctable);
159 513 : return true;
160 : }
161 0 : return false;
162 : }
163 :
164 0 : bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
165 : size_t srcRowBytes, int x, int y) {
166 : // since we don't stop creating un-pixeled devices yet, check for no pixels here
167 0 : if (nullptr == fBitmap.getPixels()) {
168 0 : return false;
169 : }
170 :
171 0 : if (fBitmap.writePixels(SkPixmap(srcInfo, srcPixels, srcRowBytes), x, y)) {
172 0 : fBitmap.notifyPixelsChanged();
173 0 : return true;
174 : }
175 0 : return false;
176 : }
177 :
178 0 : bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
179 : int x, int y) {
180 0 : return fBitmap.readPixels(dstInfo, dstPixels, dstRowBytes, x, y);
181 : }
182 :
183 : ///////////////////////////////////////////////////////////////////////////////
184 :
185 452 : class SkBitmapDevice::BDDraw : public SkDraw {
186 : public:
187 452 : BDDraw(SkBitmapDevice* dev) {
188 : // we need fDst to be set, and if we're actually drawing, to dirty the genID
189 452 : if (!dev->accessPixels(&fDst)) {
190 : // NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels
191 0 : fDst.reset(dev->imageInfo(), nullptr, 0);
192 : }
193 452 : fMatrix = &dev->ctm();
194 452 : fRC = &dev->fRCStack.rc();
195 452 : }
196 : };
197 :
198 17 : void SkBitmapDevice::drawPaint(const SkPaint& paint) {
199 17 : BDDraw(this).drawPaint(paint);
200 17 : }
201 :
202 13 : void SkBitmapDevice::drawPoints(SkCanvas::PointMode mode, size_t count,
203 : const SkPoint pts[], const SkPaint& paint) {
204 13 : BDDraw(this).drawPoints(mode, count, pts, paint, nullptr);
205 13 : }
206 :
207 188 : void SkBitmapDevice::drawRect(const SkRect& r, const SkPaint& paint) {
208 188 : BDDraw(this).drawRect(r, paint);
209 188 : }
210 :
211 0 : void SkBitmapDevice::drawOval(const SkRect& oval, const SkPaint& paint) {
212 0 : SkPath path;
213 0 : path.addOval(oval);
214 : // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
215 : // required to override drawOval.
216 0 : this->drawPath(path, paint, nullptr, true);
217 0 : }
218 :
219 0 : void SkBitmapDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
220 : #ifdef SK_IGNORE_BLURRED_RRECT_OPT
221 : SkPath path;
222 :
223 : path.addRRect(rrect);
224 : // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
225 : // required to override drawRRect.
226 : this->drawPath(path, paint, nullptr, true);
227 : #else
228 0 : BDDraw(this).drawRRect(rrect, paint);
229 : #endif
230 0 : }
231 :
232 61 : void SkBitmapDevice::drawPath(const SkPath& path,
233 : const SkPaint& paint, const SkMatrix* prePathMatrix,
234 : bool pathIsMutable) {
235 61 : BDDraw(this).drawPath(path, paint, prePathMatrix, pathIsMutable);
236 61 : }
237 :
238 4 : void SkBitmapDevice::drawBitmap(const SkBitmap& bitmap,
239 : const SkMatrix& matrix, const SkPaint& paint) {
240 4 : LogDrawScaleFactor(SkMatrix::Concat(this->ctm(), matrix), paint.getFilterQuality());
241 4 : BDDraw(this).drawBitmap(bitmap, matrix, nullptr, paint);
242 4 : }
243 :
244 126 : static inline bool CanApplyDstMatrixAsCTM(const SkMatrix& m, const SkPaint& paint) {
245 126 : if (!paint.getMaskFilter()) {
246 126 : return true;
247 : }
248 :
249 : // Some mask filters parameters (sigma) depend on the CTM/scale.
250 0 : return m.getType() <= SkMatrix::kTranslate_Mask;
251 : }
252 :
253 140 : void SkBitmapDevice::drawBitmapRect(const SkBitmap& bitmap,
254 : const SkRect* src, const SkRect& dst,
255 : const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) {
256 : SkMatrix matrix;
257 : SkRect bitmapBounds, tmpSrc, tmpDst;
258 154 : SkBitmap tmpBitmap;
259 :
260 140 : bitmapBounds.isetWH(bitmap.width(), bitmap.height());
261 :
262 : // Compute matrix from the two rectangles
263 140 : if (src) {
264 140 : tmpSrc = *src;
265 : } else {
266 0 : tmpSrc = bitmapBounds;
267 : }
268 140 : matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
269 :
270 140 : LogDrawScaleFactor(SkMatrix::Concat(this->ctm(), matrix), paint.getFilterQuality());
271 :
272 140 : const SkRect* dstPtr = &dst;
273 140 : const SkBitmap* bitmapPtr = &bitmap;
274 :
275 : // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
276 : // needed (if the src was clipped). No check needed if src==null.
277 140 : if (src) {
278 140 : if (!bitmapBounds.contains(*src)) {
279 0 : if (!tmpSrc.intersect(bitmapBounds)) {
280 0 : return; // nothing to draw
281 : }
282 : // recompute dst, based on the smaller tmpSrc
283 0 : matrix.mapRect(&tmpDst, tmpSrc);
284 0 : dstPtr = &tmpDst;
285 : }
286 : }
287 :
288 280 : if (src && !src->contains(bitmapBounds) &&
289 140 : SkCanvas::kFast_SrcRectConstraint == constraint &&
290 0 : paint.getFilterQuality() != kNone_SkFilterQuality) {
291 : // src is smaller than the bounds of the bitmap, and we are filtering, so we don't know
292 : // how much more of the bitmap we need, so we can't use extractSubset or drawBitmap,
293 : // but we must use a shader w/ dst bounds (which can access all of the bitmap needed).
294 0 : goto USE_SHADER;
295 : }
296 :
297 140 : if (src) {
298 : // since we may need to clamp to the borders of the src rect within
299 : // the bitmap, we extract a subset.
300 140 : const SkIRect srcIR = tmpSrc.roundOut();
301 140 : if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
302 0 : return;
303 : }
304 140 : bitmapPtr = &tmpBitmap;
305 :
306 : // Since we did an extract, we need to adjust the matrix accordingly
307 140 : SkScalar dx = 0, dy = 0;
308 140 : if (srcIR.fLeft > 0) {
309 12 : dx = SkIntToScalar(srcIR.fLeft);
310 : }
311 140 : if (srcIR.fTop > 0) {
312 12 : dy = SkIntToScalar(srcIR.fTop);
313 : }
314 140 : if (dx || dy) {
315 14 : matrix.preTranslate(dx, dy);
316 : }
317 :
318 : #ifdef SK_DRAWBITMAPRECT_FAST_OFFSET
319 : SkRect extractedBitmapBounds = SkRect::MakeXYWH(dx, dy,
320 : SkIntToScalar(bitmapPtr->width()),
321 : SkIntToScalar(bitmapPtr->height()));
322 : #else
323 : SkRect extractedBitmapBounds;
324 140 : extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
325 : #endif
326 140 : if (extractedBitmapBounds == tmpSrc) {
327 : // no fractional part in src, we can just call drawBitmap
328 126 : goto USE_DRAWBITMAP;
329 : }
330 : } else {
331 : USE_DRAWBITMAP:
332 : // We can go faster by just calling drawBitmap, which will concat the
333 : // matrix with the CTM, and try to call drawSprite if it can. If not,
334 : // it will make a shader and call drawRect, as we do below.
335 126 : if (CanApplyDstMatrixAsCTM(matrix, paint)) {
336 126 : BDDraw(this).drawBitmap(*bitmapPtr, matrix, dstPtr, paint);
337 126 : return;
338 : }
339 : }
340 :
341 : USE_SHADER:
342 :
343 : // TODO(herb): Move this over to SkArenaAlloc when arena alloc has a facility to return sk_sps.
344 : // Since the shader need only live for our stack-frame, pass in a custom allocator. This
345 : // can save malloc calls, and signals to SkMakeBitmapShader to not try to copy the bitmap
346 : // if its mutable, since that precaution is not needed (give the short lifetime of the shader).
347 :
348 : // construct a shader, so we can call drawRect with the dst
349 : auto s = SkMakeBitmapShader(*bitmapPtr, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
350 28 : &matrix, kNever_SkCopyPixelsMode);
351 14 : if (!s) {
352 0 : return;
353 : }
354 :
355 28 : SkPaint paintWithShader(paint);
356 14 : paintWithShader.setStyle(SkPaint::kFill_Style);
357 14 : paintWithShader.setShader(s);
358 :
359 : // Call ourself, in case the subclass wanted to share this setup code
360 : // but handle the drawRect code themselves.
361 14 : this->drawRect(*dstPtr, paintWithShader);
362 : }
363 :
364 3 : void SkBitmapDevice::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) {
365 3 : BDDraw(this).drawSprite(bitmap, x, y, paint);
366 3 : }
367 :
368 0 : void SkBitmapDevice::drawText(const void* text, size_t len,
369 : SkScalar x, SkScalar y, const SkPaint& paint) {
370 0 : BDDraw(this).drawText((const char*)text, len, x, y, paint, &fSurfaceProps);
371 0 : }
372 :
373 21 : void SkBitmapDevice::drawPosText(const void* text, size_t len, const SkScalar xpos[],
374 : int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) {
375 42 : BDDraw(this).drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint,
376 21 : &fSurfaceProps);
377 21 : }
378 :
379 0 : void SkBitmapDevice::drawVertices(const SkVertices* vertices, SkBlendMode bmode,
380 : const SkPaint& paint) {
381 0 : BDDraw(this).drawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(),
382 : vertices->texCoords(), vertices->colors(), bmode,
383 0 : vertices->indices(), vertices->indexCount(), paint);
384 0 : }
385 :
386 19 : void SkBitmapDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPaint& paint) {
387 19 : SkASSERT(!paint.getImageFilter());
388 19 : BDDraw(this).drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, paint);
389 19 : }
390 :
391 : ///////////////////////////////////////////////////////////////////////////////
392 :
393 3 : void SkBitmapDevice::drawSpecial(SkSpecialImage* srcImg, int x, int y,
394 : const SkPaint& paint) {
395 3 : SkASSERT(!srcImg->isTextureBacked());
396 :
397 6 : SkBitmap resultBM;
398 :
399 3 : SkImageFilter* filter = paint.getImageFilter();
400 3 : if (filter) {
401 0 : SkIPoint offset = SkIPoint::Make(0, 0);
402 0 : SkMatrix matrix = this->ctm();
403 0 : matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
404 0 : const SkIRect clipBounds = fRCStack.rc().getBounds().makeOffset(-x, -y);
405 0 : sk_sp<SkImageFilterCache> cache(this->getImageFilterCache());
406 0 : SkImageFilter::OutputProperties outputProperties(fBitmap.colorSpace());
407 0 : SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties);
408 :
409 0 : sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset));
410 0 : if (resultImg) {
411 0 : SkPaint tmpUnfiltered(paint);
412 0 : tmpUnfiltered.setImageFilter(nullptr);
413 0 : if (resultImg->getROPixels(&resultBM)) {
414 0 : this->drawSprite(resultBM, x + offset.x(), y + offset.y(), tmpUnfiltered);
415 : }
416 : }
417 : } else {
418 3 : if (srcImg->getROPixels(&resultBM)) {
419 3 : this->drawSprite(resultBM, x, y, paint);
420 : }
421 : }
422 3 : }
423 :
424 3 : sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkBitmap& bitmap) {
425 3 : return SkSpecialImage::MakeFromRaster(bitmap.bounds(), bitmap);
426 : }
427 :
428 0 : sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkImage* image) {
429 0 : return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->height()),
430 0 : image->makeNonTextureImage(), fBitmap.colorSpace());
431 : }
432 :
433 3 : sk_sp<SkSpecialImage> SkBitmapDevice::snapSpecial() {
434 3 : return this->makeSpecial(fBitmap);
435 : }
436 :
437 : ///////////////////////////////////////////////////////////////////////////////
438 :
439 0 : sk_sp<SkSurface> SkBitmapDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
440 0 : return SkSurface::MakeRaster(info, &props);
441 : }
442 :
443 0 : SkImageFilterCache* SkBitmapDevice::getImageFilterCache() {
444 0 : SkImageFilterCache* cache = SkImageFilterCache::Get();
445 0 : cache->ref();
446 0 : return cache;
447 : }
448 :
449 : ///////////////////////////////////////////////////////////////////////////////////////////////////
450 :
451 21 : bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const {
452 63 : if (kN32_SkColorType != fBitmap.colorType() ||
453 42 : paint.getRasterizer() ||
454 42 : paint.getPathEffect() ||
455 42 : paint.isFakeBoldText() ||
456 63 : paint.getStyle() != SkPaint::kFill_Style ||
457 21 : !paint.isSrcOver())
458 : {
459 0 : return true;
460 : }
461 21 : return false;
462 : }
463 :
464 : ///////////////////////////////////////////////////////////////////////////////////////////////////
465 :
466 617 : void SkBitmapDevice::onSave() {
467 617 : fRCStack.save();
468 617 : }
469 :
470 617 : void SkBitmapDevice::onRestore() {
471 617 : fRCStack.restore();
472 617 : }
473 :
474 532 : void SkBitmapDevice::onClipRect(const SkRect& rect, SkClipOp op, bool aa) {
475 532 : fRCStack.clipRect(this->ctm(), rect, op, aa);
476 532 : }
477 :
478 0 : void SkBitmapDevice::onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) {
479 0 : fRCStack.clipRRect(this->ctm(), rrect, op, aa);
480 0 : }
481 :
482 39 : void SkBitmapDevice::onClipPath(const SkPath& path, SkClipOp op, bool aa) {
483 39 : fRCStack.clipPath(this->ctm(), path, op, aa);
484 39 : }
485 :
486 24 : void SkBitmapDevice::onClipRegion(const SkRegion& rgn, SkClipOp op) {
487 24 : SkIPoint origin = this->getOrigin();
488 48 : SkRegion tmp;
489 24 : const SkRegion* ptr = &rgn;
490 24 : if (origin.fX | origin.fY) {
491 : // translate from "global/canvas" coordinates to relative to this device
492 0 : rgn.translate(-origin.fX, -origin.fY, &tmp);
493 0 : ptr = &tmp;
494 : }
495 24 : fRCStack.clipRegion(*ptr, op);
496 24 : }
497 :
498 85 : void SkBitmapDevice::onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) {
499 85 : fRCStack.setDeviceClipRestriction(mutableClipRestriction);
500 85 : if (!mutableClipRestriction->isEmpty()) {
501 0 : SkRegion rgn(*mutableClipRestriction);
502 0 : fRCStack.clipRegion(rgn, SkClipOp::kIntersect);
503 : }
504 85 : }
505 :
506 0 : bool SkBitmapDevice::onClipIsAA() const {
507 0 : const SkRasterClip& rc = fRCStack.rc();
508 0 : return !rc.isEmpty() && rc.isAA();
509 : }
510 :
511 0 : void SkBitmapDevice::onAsRgnClip(SkRegion* rgn) const {
512 0 : const SkRasterClip& rc = fRCStack.rc();
513 0 : if (rc.isAA()) {
514 0 : rgn->setRect(rc.getBounds());
515 : } else {
516 0 : *rgn = rc.bwRgn();
517 : }
518 0 : }
519 :
520 0 : void SkBitmapDevice::validateDevBounds(const SkIRect& drawClipBounds) {
521 : #ifdef SK_DEBUG
522 0 : const SkIRect& stackBounds = fRCStack.rc().getBounds();
523 0 : SkASSERT(drawClipBounds == stackBounds);
524 : #endif
525 0 : }
526 :
527 0 : SkBaseDevice::ClipType SkBitmapDevice::onGetClipType() const {
528 0 : const SkRasterClip& rc = fRCStack.rc();
529 0 : if (rc.isEmpty()) {
530 0 : return kEmpty_ClipType;
531 0 : } else if (rc.isRect()) {
532 0 : return kRect_ClipType;
533 : } else {
534 0 : return kComplex_ClipType;
535 : }
536 : }
|