| |
| /* |
| * Copyright 2010 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| |
| |
| #include "GrClip.h" |
| |
| GrClip::GrClip() { |
| fConservativeBounds.setEmpty(); |
| fConservativeBoundsValid = true; |
| } |
| |
| GrClip::GrClip(const GrClip& src) { |
| *this = src; |
| } |
| |
| GrClip::GrClip(const GrIRect& rect) { |
| this->setFromIRect(rect); |
| } |
| |
| GrClip::GrClip(const GrRect& rect) { |
| this->setFromRect(rect); |
| } |
| |
| GrClip::GrClip(GrClipIterator* iter, GrScalar tx, GrScalar ty, |
| const GrRect* bounds) { |
| this->setFromIterator(iter, tx, ty, bounds); |
| } |
| |
| GrClip::~GrClip() {} |
| |
| GrClip& GrClip::operator=(const GrClip& src) { |
| fList = src.fList; |
| fConservativeBounds = src.fConservativeBounds; |
| fConservativeBoundsValid = src.fConservativeBoundsValid; |
| return *this; |
| } |
| |
| void GrClip::setEmpty() { |
| fList.reset(); |
| fConservativeBounds.setEmpty(); |
| fConservativeBoundsValid = true; |
| } |
| |
| void GrClip::setFromRect(const GrRect& r) { |
| fList.reset(); |
| if (r.isEmpty()) { |
| // use a canonical empty rect for == testing. |
| setEmpty(); |
| } else { |
| fList.push_back(); |
| fList.back().fRect = r; |
| fList.back().fType = kRect_ClipType; |
| fList.back().fOp = kReplace_SetOp; |
| fConservativeBounds = r; |
| fConservativeBoundsValid = true; |
| } |
| } |
| |
| void GrClip::setFromIRect(const GrIRect& r) { |
| fList.reset(); |
| if (r.isEmpty()) { |
| // use a canonical empty rect for == testing. |
| setEmpty(); |
| } else { |
| fList.push_back(); |
| fList.back().fRect.set(r); |
| fList.back().fType = kRect_ClipType; |
| fList.back().fOp = kReplace_SetOp; |
| fConservativeBounds.set(r); |
| fConservativeBoundsValid = true; |
| } |
| } |
| |
| static void intersectWith(SkRect* dst, const SkRect& src) { |
| if (!dst->intersect(src)) { |
| dst->setEmpty(); |
| } |
| } |
| |
| void GrClip::setFromIterator(GrClipIterator* iter, GrScalar tx, GrScalar ty, |
| const GrRect* conservativeBounds) { |
| fList.reset(); |
| |
| int rectCount = 0; |
| |
| // compute bounds for common case of series of intersecting rects. |
| bool isectRectValid = true; |
| |
| if (iter) { |
| for (iter->rewind(); !iter->isDone(); iter->next()) { |
| Element& e = fList.push_back(); |
| e.fType = iter->getType(); |
| e.fOp = iter->getOp(); |
| // iterators should not emit replace |
| GrAssert(kReplace_SetOp != e.fOp); |
| switch (e.fType) { |
| case kRect_ClipType: |
| iter->getRect(&e.fRect); |
| if (tx || ty) { |
| e.fRect.offset(tx, ty); |
| } |
| ++rectCount; |
| if (isectRectValid) { |
| if (kIntersect_SetOp == e.fOp) { |
| GrAssert(fList.count() <= 2); |
| if (fList.count() > 1) { |
| GrAssert(2 == rectCount); |
| rectCount = 1; |
| fList.pop_back(); |
| GrAssert(kRect_ClipType == fList.back().fType); |
| intersectWith(&fList.back().fRect, e.fRect); |
| } |
| } else { |
| isectRectValid = false; |
| } |
| } |
| break; |
| case kPath_ClipType: |
| e.fPath = *iter->getPath(); |
| if (tx || ty) { |
| e.fPath.offset(tx, ty); |
| } |
| e.fPathFill = iter->getPathFill(); |
| isectRectValid = false; |
| break; |
| default: |
| GrCrash("Unknown clip element type."); |
| } |
| } |
| } |
| fConservativeBoundsValid = false; |
| if (isectRectValid && rectCount) { |
| fConservativeBounds = fList[0].fRect; |
| fConservativeBoundsValid = true; |
| } else if (NULL != conservativeBounds) { |
| fConservativeBounds = *conservativeBounds; |
| fConservativeBoundsValid = true; |
| } |
| } |