| Index: src/gpu/draws/GrDrawRect.cpp | 
| diff --git a/src/gpu/draws/GrDrawRect.cpp b/src/gpu/draws/GrDrawRect.cpp | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..22b98208dd2aecfe2bcaed771c61f1014d050808 | 
| --- /dev/null | 
| +++ b/src/gpu/draws/GrDrawRect.cpp | 
| @@ -0,0 +1,215 @@ | 
| +/* | 
| + * Copyright 2015 Google Inc. | 
| + * | 
| + * Use of this source code is governed by a BSD-style license that can be | 
| + * found in the LICENSE file. | 
| + */ | 
| + | 
| +#include "GrDrawRect.h" | 
| + | 
| +#include "GrContext.h" | 
| +#include "GrClip.h" | 
| +#include "GrDrawTarget.h" | 
| +#include "GrRenderTarget.h" | 
| +#include "GrStrokeInfo.h" | 
| +#include "SkColorFilter.h" | 
| +#include "SkImageFilter.h" | 
| +#include "SkGr.h" | 
| +#include "SkMatrix.h" | 
| +#include "SkMaskFilter.h" | 
| +#include "SkPaint.h" | 
| +#include "SkRect.h" | 
| +#include "SkShader.h" | 
| +#include "SkXfermode.h" | 
| +#include "batches/GrRectBatchFactory.h" | 
| + | 
| +enum RectBatchType { | 
| +    kAAStroke_RectBatchType, | 
| +    kAAFill_RectBatchType, | 
| +    kNonAAFill_RectBatchType, | 
| +    kNonAAStroke_RectBatchType, | 
| +}; | 
| + | 
| +class GrDrawRectSnap : public GrDrawSnap { | 
| +public: | 
| +    GrDrawRectSnap(const SkPaint& paint, | 
| +                   const GrClip& clip, | 
| +                   RectBatchType type, | 
| +                   bool snapToPixelCenter) | 
| +        : fShader(SkSafeRef(paint.getShader())) | 
| +        , fMaskFilter(SkSafeRef(paint.getMaskFilter())) | 
| +        , fImageFilter(SkSafeRef(paint.getImageFilter())) | 
| +        , fColorFilter(SkSafeRef(paint.getColorFilter())) | 
| +        , fClipGenID(clip.clipType() != GrClip::kClipStack_ClipType ? | 
| +                     -1 : | 
| +                     clip.clipStack()->getTopmostGenID()) | 
| +        , fType(type) | 
| +        , fSnapToPixelCenters(snapToPixelCenter) | 
| +        , fIsDither(paint.isDither()) { | 
| +        fClassID = GrDrawRect::ClassID(); | 
| +    } | 
| + | 
| +    bool canBatch(const SkPaint& paint, | 
| +                  const GrClip& clip, | 
| +                  RectBatchType type, | 
| +                  bool snapToPixelCenters) const { | 
| +        return paint.getShader() == fShader && | 
| +               paint.getMaskFilter() == fMaskFilter && | 
| +               paint.getImageFilter() == fImageFilter && | 
| +               paint.getColorFilter() == fColorFilter && | 
| +               paint.isDither() == fIsDither && | 
| +               fClipGenID != -1 && clip.clipType() == GrClip::kClipStack_ClipType && | 
| +               fClipGenID == clip.clipStack()->getTopmostGenID() && | 
| +               fType == type && | 
| +               fSnapToPixelCenters == snapToPixelCenters; | 
| +    } | 
| + | 
| +    // we only bother fast pathing kSrcOver_Mode, though we could do quite a bit more | 
| +    static bool CanSnap(const SkPaint& paint) { | 
| +        return SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode); | 
| +    } | 
| + | 
| +private: | 
| +    SkAutoTUnref<SkShader> fShader; | 
| +    SkAutoTUnref<SkMaskFilter> fMaskFilter; | 
| +    SkAutoTUnref<SkImageFilter> fImageFilter; | 
| +    SkAutoTUnref<SkColorFilter> fColorFilter; | 
| +    int32_t fClipGenID; | 
| +    RectBatchType fType; | 
| +    bool fSnapToPixelCenters; | 
| +    bool fIsDither; | 
| + | 
| +    typedef GrDrawSnap INHERITED; | 
| +}; | 
| + | 
| +inline static RectBatchType compute_rect_batch_type(bool useAA, SkScalar width) { | 
| +    if (useAA) { | 
| +        if (width >= 0) { | 
| +            return kAAStroke_RectBatchType; | 
| +        } else { | 
| +            return kAAFill_RectBatchType; | 
| +        } | 
| +    } else if (width >= 0) { | 
| +        return kNonAAStroke_RectBatchType; | 
| +    } else { | 
| +        return kNonAAFill_RectBatchType; | 
| +    } | 
| +} | 
| + | 
| +inline static bool can_fastpath(GrDrawTarget* drawTarget, | 
| +                                const SkPaint& paint, | 
| +                                const GrClip& clip, | 
| +                                GrColor color, | 
| +                                const SkMatrix& viewMatrix, | 
| +                                const SkRect& rect, | 
| +                                const GrStrokeInfo& strokeInfo, | 
| +                                RectBatchType batchType, | 
| +                                bool snapToPixelCenters) { | 
| +    GrBatch* lastBatch = drawTarget->lastBatch(); | 
| +    if (!lastBatch) { | 
| +        return false; | 
| +    } | 
| + | 
| +    const GrDrawSnap* lastSnap = lastBatch->drawSnap(); | 
| +    if (!lastSnap) { | 
| +        return false; | 
| +    } | 
| + | 
| +    if (lastSnap->classID() != GrDrawRect::ClassID()) { | 
| +        return false; | 
| +    } | 
| + | 
| +    const GrDrawRectSnap* lastSnapCast = static_cast<const GrDrawRectSnap*>(lastSnap); | 
| +    if (lastSnapCast->canBatch(paint, clip, batchType, snapToPixelCenters)) { | 
| +        switch (batchType) { | 
| +            case kAAStroke_RectBatchType: | 
| +                if (GrAAStrokeRectBatch::Append(lastBatch, color, viewMatrix, rect, | 
| +                                                strokeInfo)) { | 
| +                    return true; | 
| +                } | 
| +                break; | 
| +            case kAAFill_RectBatchType: | 
| +                GrAAFillRectBatch::Append(lastBatch, color, viewMatrix, rect); | 
| +                return true; | 
| +            case kNonAAFill_RectBatchType: | 
| +                if (GrNonAAFillRectBatch::Append(lastBatch, color, viewMatrix, rect, | 
| +                                                 nullptr, nullptr)) { | 
| +                    return true; | 
| +                } | 
| +                break; | 
| +            case kNonAAStroke_RectBatchType: | 
| +                // GrNonAAStrokeRectBatch doesn't batch yet | 
| +                break; | 
| +        } | 
| +    } | 
| + | 
| +    return false; | 
| +} | 
| + | 
| +void GrDrawRect::execute(GrDrawTarget* drawTarget) const { | 
| +    const SkPaint& paint = *fPaint; | 
| +    const GrClip& clip = *fClip; | 
| +    const SkMatrix& viewMatrix = *fViewMatrix; | 
| +    const SkRect& rect = *fRect; | 
| + | 
| +    SkScalar width = nullptr == fStrokeInfo ? -1 : fStrokeInfo->getWidth(); | 
| + | 
| +    bool needAA = fPaint->isAntiAlias() && !fRenderTarget->isUnifiedMultisampled(); | 
| + | 
| +    // The fill path can handle rotation but not skew | 
| +    // The stroke path needs the rect to remain axis aligned (no rotation or skew) | 
| +    // None of our AA draw rect calls can handle perspective yet | 
| +    bool canApplyAA = width >= 0 ? viewMatrix.rectStaysRect() : viewMatrix.preservesRightAngles(); | 
| +    bool useAA = needAA && canApplyAA; | 
| + | 
| +    // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic | 
| +    bool snapToPixelCenters = !useAA && (0 == width && !fRenderTarget->isUnifiedMultisampled()); | 
| + | 
| +    // TODO we also do this on the paint, do we need to? | 
| +    SkColor paintColor = paint.getColor(); | 
| +    if (fPaint->getColorFilter() && !paint.getShader()) { | 
| +        paintColor = paint.getColorFilter()->filterColor(paintColor); | 
| +    } | 
| +    GrColor color = SkColor2GrColor(paintColor); | 
| + | 
| +    RectBatchType batchType = compute_rect_batch_type(useAA, width); | 
| +    if (can_fastpath(drawTarget, *fPaint, clip, color, viewMatrix, rect, *fStrokeInfo, batchType, | 
| +                     snapToPixelCenters)) { | 
| +        return; | 
| +    } | 
| + | 
| +    SkAutoTUnref<GrDrawBatch> batch; | 
| +    switch (batchType) { | 
| +        case kAAStroke_RectBatchType: | 
| +            batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect, *fStrokeInfo)); | 
| +            break; | 
| +        case kAAFill_RectBatchType: | 
| +            batch.reset(GrRectBatchFactory::CreateAAFill(color, viewMatrix, rect)); | 
| +            break; | 
| +        case kNonAAFill_RectBatchType: | 
| +            batch.reset(GrRectBatchFactory::CreateNonAAFill(color, viewMatrix, rect, nullptr, | 
| +                                                            nullptr)); | 
| +            break; | 
| +        case kNonAAStroke_RectBatchType: | 
| +            batch.reset(GrRectBatchFactory::CreateNonAAStroke(color, viewMatrix, rect, width, | 
| +                                                              snapToPixelCenters)); | 
| +            break; | 
| +    } | 
| + | 
| +    GrPaint grPaint; | 
| +    if (!SkPaint2GrPaint(fContext, fRenderTarget, paint, viewMatrix, true, &grPaint)) { | 
| +        return; | 
| +    } | 
| + | 
| +    GrPipelineBuilder pipelineBuilder(grPaint, fRenderTarget, clip); | 
| + | 
| +    // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of | 
| +    // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA | 
| +    // is enabled because it can cause ugly artifacts. | 
| +    pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag, | 
| +                             snapToPixelCenters); | 
| +    drawTarget->drawBatch(pipelineBuilder, batch); | 
| +    if (GrDrawRectSnap::CanSnap(paint)) { | 
| +        batch->setDrawSnap(new GrDrawRectSnap(paint, clip, batchType, snapToPixelCenters)); | 
| +    } | 
| +} | 
|  |