示例#1
0
 LcdTextGM() {
     const int pointSize = 36;
     textHeight = SkIntToScalar(pointSize);
 }
示例#2
0
    virtual void onDraw(SkCanvas* canvas) {
        SkScalar x = SkIntToScalar(100);
        SkScalar y = SkIntToScalar(88);

        SkPaint paint;
        paint.setAntiAlias(true);
        paint.setTextSize(SkIntToScalar(100));
        paint.setStrokeWidth(SkIntToScalar(5));

        SkTypeface* face = SkTypeface::CreateFromName("Papyrus", SkTypeface::kNormal);
        SkSafeUnref(paint.setTypeface(face));
        show_bold(canvas, "Hello", 5, x, y, paint);

        face = SkTypeface::CreateFromName("Hiragino Maru Gothic Pro", SkTypeface::kNormal);
        SkSafeUnref(paint.setTypeface(face));
        const unsigned char hyphen[] = { 0xE3, 0x83, 0xBC };
        show_bold(canvas, hyphen, SK_ARRAY_COUNT(hyphen), x + SkIntToScalar(300), y, paint);

        paint.setStyle(SkPaint::kStrokeAndFill_Style);

        SkPath path;
        path.setFillType(SkPath::kWinding_FillType);
        path.addCircle(x, y + SkIntToScalar(200), SkIntToScalar(50), SkPath::kCW_Direction);
        path.addCircle(x, y + SkIntToScalar(200), SkIntToScalar(40), SkPath::kCCW_Direction);
        canvas->drawPath(path, paint);

        SkPath path2;
        path2.setFillType(SkPath::kWinding_FillType);
        path2.addCircle(x + SkIntToScalar(120), y + SkIntToScalar(200), SkIntToScalar(50), SkPath::kCCW_Direction);
        path2.addCircle(x + SkIntToScalar(120), y + SkIntToScalar(200), SkIntToScalar(40), SkPath::kCW_Direction);
        canvas->drawPath(path2, paint);

        path2.reset();
        path2.addCircle(x + SkIntToScalar(240), y + SkIntToScalar(200), SkIntToScalar(50), SkPath::kCCW_Direction);
        canvas->drawPath(path2, paint);
        SkASSERT(path2.cheapIsDirection(SkPath::kCCW_Direction));

        path2.reset();
        SkASSERT(!path2.cheapComputeDirection(NULL));
        path2.addCircle(x + SkIntToScalar(360), y + SkIntToScalar(200), SkIntToScalar(50), SkPath::kCW_Direction);
        SkASSERT(path2.cheapIsDirection(SkPath::kCW_Direction));
        canvas->drawPath(path2, paint);
    }
示例#3
0
////////////////////////////////////////////////////////////////////////////////
// Create a 8-bit clip mask in alpha
bool GrClipMaskManager::createAlphaClipMask(const GrClipData& clipDataIn,
                                            GrTexture** result,
                                            GrIRect *devResultBounds) {
    GrAssert(NULL != devResultBounds);
    GrAssert(kNone_ClipMaskType == fCurrClipMaskType);

    if (this->clipMaskPreamble(clipDataIn, result, devResultBounds)) {
        fCurrClipMaskType = kAlpha_ClipMaskType;
        return true;
    }

    // Note: 'resultBounds' is in device (as opposed to canvas) coordinates

    GrTexture* accum = fAACache.getLastMask();
    if (NULL == accum) {
        fAACache.reset();
        return false;
    }

    GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
    GrDrawState* drawState = fGpu->drawState();

    GrDrawTarget::AutoGeometryPush agp(fGpu);

    if (0 != devResultBounds->fTop || 0 != devResultBounds->fLeft ||
        0 != clipDataIn.fOrigin.fX || 0 != clipDataIn.fOrigin.fY) {
        // if we were able to trim down the size of the mask we need to
        // offset the paths & rects that will be used to compute it
        drawState->viewMatrix()->setTranslate(
                SkIntToScalar(-devResultBounds->fLeft-clipDataIn.fOrigin.fX),
                SkIntToScalar(-devResultBounds->fTop-clipDataIn.fOrigin.fY));
    }

    bool clearToInside;
    SkRegion::Op firstOp = SkRegion::kReplace_Op; // suppress warning

    SkClipStack::Iter iter(*clipDataIn.fClipStack,
                           SkClipStack::Iter::kBottom_IterStart);
    const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter,
                                                              *devResultBounds,
                                                              &clearToInside,
                                                              &firstOp,
                                                              clipDataIn);

    fGpu->clear(NULL,
                clearToInside ? 0xffffffff : 0x00000000,
                accum->asRenderTarget());

    GrAutoScratchTexture temp;
    bool first = true;
    // walk through each clip element and perform its set op
    for ( ; NULL != clip; clip = iter.next()) {

        SkRegion::Op op = clip->fOp;
        if (first) {
            first = false;
            op = firstOp;
        }

        if (SkRegion::kReplace_Op == op) {
            // clear the accumulator and draw the new object directly into it
            fGpu->clear(NULL, 0x00000000, accum->asRenderTarget());

            setup_boolean_blendcoeffs(drawState, op);
            this->drawClipShape(accum, clip, *devResultBounds);

        } else if (SkRegion::kReverseDifference_Op == op ||
                   SkRegion::kIntersect_Op == op) {
            // there is no point in intersecting a screen filling rectangle.
            if (SkRegion::kIntersect_Op == op && NULL != clip->fRect &&
                contains(*clip->fRect, *devResultBounds, clipDataIn.fOrigin)) {
                continue;
            }

            getTemp(*devResultBounds, &temp);
            if (NULL == temp.texture()) {
                fAACache.reset();
                return false;
            }

            // clear the temp target & draw into it
            fGpu->clear(NULL, 0x00000000, temp.texture()->asRenderTarget());

            setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op);
            this->drawClipShape(temp.texture(), clip, *devResultBounds);

            // TODO: rather than adding these two translations here
            // compute the bounding box needed to render the texture
            // into temp
            if (0 != devResultBounds->fTop || 0 != devResultBounds->fLeft ||
                0 != clipDataIn.fOrigin.fX || 0 != clipDataIn.fOrigin.fY) {
                // In order for the merge of the temp clip into the accumulator
                // to work we need to disable the translation
                drawState->viewMatrix()->reset();
            }

            // Now draw into the accumulator using the real operation
            // and the temp buffer as a texture
            setup_boolean_blendcoeffs(drawState, op);
            this->drawTexture(accum, temp.texture());

            if (0 != devResultBounds->fTop || 0 != devResultBounds->fLeft ||
                0 != clipDataIn.fOrigin.fX || 0 != clipDataIn.fOrigin.fY) {
                drawState->viewMatrix()->setTranslate(
                  SkIntToScalar(-devResultBounds->fLeft-clipDataIn.fOrigin.fX),
                  SkIntToScalar(-devResultBounds->fTop-clipDataIn.fOrigin.fY));
            }

        } else {
            // all the remaining ops can just be directly draw into
            // the accumulation buffer
            setup_boolean_blendcoeffs(drawState, op);
            this->drawClipShape(accum, clip, *devResultBounds);
        }
    }

    *result = accum;
    fCurrClipMaskType = kAlpha_ClipMaskType;
    return true;
}
示例#4
0
文件: shapes.cpp 项目: BBKeeper/Skia
static SkRect make_rect(int l, int t, int r, int b) {
    SkRect rect;
    rect.set(SkIntToScalar(l), SkIntToScalar(t),
             SkIntToScalar(r), SkIntToScalar(b));
    return rect;
}
示例#5
0
文件: shadows.cpp 项目: Arternis/skia
 void onOnceBeforeDraw() override {
     this->setBGColor(0xFFDDDDDD);
     fCirclePath.addCircle(SkIntToScalar(20), SkIntToScalar(20), SkIntToScalar(10) );
     fRect.set(SkIntToScalar(10), SkIntToScalar(10),
               SkIntToScalar(30), SkIntToScalar(30));
 }
示例#6
0
static SkRect make_rect() {
    return SkRect::MakeWH(SkIntToScalar(R(static_cast<float>(kBitmapSize))),
                          SkIntToScalar(R(static_cast<float>(kBitmapSize))));
}
示例#7
0
    { SkXfermode::kSrc_Mode,      "Src"       },
    { SkXfermode::kDst_Mode,      "Dst"       },
    { SkXfermode::kSrcOver_Mode,  "SrcOver"   },
    { SkXfermode::kDstOver_Mode,  "DstOver"   },
    { SkXfermode::kSrcIn_Mode,    "SrcIn"     },
    { SkXfermode::kDstIn_Mode,    "DstIn"     },
    { SkXfermode::kSrcOut_Mode,   "SrcOut"    },
    { SkXfermode::kDstOut_Mode,   "DstOut"    },
    { SkXfermode::kSrcATop_Mode,  "SrcATop"   },
    { SkXfermode::kDstATop_Mode,  "DstATop"   },
    { SkXfermode::kXor_Mode,      "Xor"       },
};

const int gWidth = 64;
const int gHeight = 64;
const SkScalar W = SkIntToScalar(gWidth);
const SkScalar H = SkIntToScalar(gHeight);

static SkScalar drawCell(SkCanvas* canvas, SkXfermode* mode,
                         SkAlpha a0, SkAlpha a1) {

    SkPaint paint;
    paint.setAntiAlias(true);

    SkRect r = SkRect::MakeWH(W, H);
    r.inset(W/10, H/10);

    paint.setColor(SK_ColorBLUE);
    paint.setAlpha(a0);
    canvas->drawOval(r, paint);
示例#8
0
    }

    void setAssertMessageFormat(const char* format) {
        fAssertMessageFormat = format;
    }

private:
    SkString fAssertMessage;
    const char* fAssertMessageFormat;
};

///////////////////////////////////////////////////////////////////////////////
// Constants used by test steps

const SkRect kTestRect = 
    SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
                     SkIntToScalar(2), SkIntToScalar(1));
static SkMatrix testMatrix() {
    SkMatrix matrix;
    matrix.reset();
    matrix.setScale(SkIntToScalar(2), SkIntToScalar(3));
    return matrix;
}
const SkMatrix kTestMatrix = testMatrix();
static SkPath testPath() {
    SkPath path;
    path.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
                                  SkIntToScalar(2), SkIntToScalar(1)));
    return path;
}
const SkPath kTestPath = testPath();
示例#9
0
static SkMatrix testMatrix() {
    SkMatrix matrix;
    matrix.reset();
    matrix.setScale(SkIntToScalar(2), SkIntToScalar(3));
    return matrix;
}
示例#10
0
bool SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx,
                                             SkBitmap* result, SkIPoint* offset) const {
    SkBitmap colorBM = src;
    SkIPoint colorOffset = SkIPoint::Make(0, 0);
    if (getColorInput() && !getColorInput()->getInputResultGPU(proxy, src, ctx, &colorBM,
                                                               &colorOffset)) {
        return false;
    }
    SkBitmap displacementBM = src;
    SkIPoint displacementOffset = SkIPoint::Make(0, 0);
    if (getDisplacementInput() &&
        !getDisplacementInput()->getInputResultGPU(proxy, src, ctx, &displacementBM,
                                                   &displacementOffset)) {
        return false;
    }
    SkIRect bounds;
    // Since GrDisplacementMapEffect does bounds checking on color pixel access, we don't need to
    // pad the color bitmap to bounds here.
    if (!this->applyCropRect(ctx, colorBM, colorOffset, &bounds)) {
        return false;
    }
    SkIRect displBounds;
    if (!this->applyCropRect(ctx, proxy, displacementBM,
                             &displacementOffset, &displBounds, &displacementBM)) {
        return false;
    }
    if (!bounds.intersect(displBounds)) {
        return false;
    }
    GrTexture* color = colorBM.getTexture();
    GrTexture* displacement = displacementBM.getTexture();
    GrContext* context = color->getContext();

    GrSurfaceDesc desc;
    desc.fFlags = kRenderTarget_GrSurfaceFlag;
    desc.fWidth = bounds.width();
    desc.fHeight = bounds.height();
    desc.fConfig = kSkia8888_GrPixelConfig;

    SkAutoTUnref<GrTexture> dst(context->textureProvider()->refScratchTexture(desc,
        GrTextureProvider::kApprox_ScratchTexMatch));

    if (!dst) {
        return false;
    }

    SkVector scale = SkVector::Make(fScale, fScale);
    ctx.ctm().mapVectors(&scale, 1);

    GrPaint paint;
    SkMatrix offsetMatrix = GrCoordTransform::MakeDivByTextureWHMatrix(displacement);
    offsetMatrix.preTranslate(SkIntToScalar(colorOffset.fX - displacementOffset.fX),
                              SkIntToScalar(colorOffset.fY - displacementOffset.fY));

    paint.addColorProcessor(
        GrDisplacementMapEffect::Create(fXChannelSelector,
                                        fYChannelSelector,
                                        scale,
                                        displacement,
                                        offsetMatrix,
                                        color,
                                        colorBM.dimensions()))->unref();
    SkIRect colorBounds = bounds;
    colorBounds.offset(-colorOffset);
    SkMatrix matrix;
    matrix.setTranslate(-SkIntToScalar(colorBounds.x()),
                        -SkIntToScalar(colorBounds.y()));
    context->drawRect(dst->asRenderTarget(), GrClip::WideOpen(), paint, matrix,
                      SkRect::Make(colorBounds));
    offset->fX = bounds.left();
    offset->fY = bounds.top();
    WrapTexture(dst, bounds.width(), bounds.height(), result);
    return true;
}
示例#11
0
        virtual void onDrawContent(SkCanvas* canvas)
            {
#ifdef SK_DEBUG
            if (true)
                {
                SkRegion a, b, c;
                test_union_bug_1505668(&a, &b, &c);

                if (false)      // draw the result of the test
                    {
                    SkPaint paint;

                    canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
                    paint.setColor(SK_ColorRED);
                    paint_rgn(canvas, a, paint);
                    paint.setColor(0x800000FF);
                    paint_rgn(canvas, b, paint);
                    paint.setColor(SK_ColorBLACK);
                    paint.setStyle(SkPaint::kStroke_Style);
                    //   paint_rgn(canvas, c, paint);
                    return;
                    }
                }
#endif

            static const struct
                {
                SkColor         fColor;
                const char*     fName;
                SkRegion::Op    fOp;
                } gOps[] =
                {
                    { SK_ColorBLACK,    "Difference",   SkRegion::kDifference_Op    },
                    { SK_ColorRED,      "Intersect",    SkRegion::kIntersect_Op     },
                    { 0xFF008800,       "Union",        SkRegion::kUnion_Op         },
                    { SK_ColorBLUE,     "XOR",          SkRegion::kXOR_Op           }
                };

            SkPaint textPaint;
            textPaint.setAntiAlias(true);
            textPaint.setTextSize(SK_Scalar1*24);

            this->drawOrig(canvas, false);
            canvas->save();
            canvas->translate(SkIntToScalar(200), 0);
            this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
            canvas->restore();

            canvas->translate(0, SkIntToScalar(200));

            for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++)
                {
                canvas->drawText(gOps[op].fName, strlen(gOps[op].fName), SkIntToScalar(75), SkIntToScalar(50), textPaint);

                this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);

                canvas->save();
                canvas->translate(0, SkIntToScalar(200));
                this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
                canvas->restore();

                canvas->translate(SkIntToScalar(200), 0);
                }
            }
void GrStencilAndCoverTextContext::init(GrRenderTarget* rt,
                                        const GrClip& clip,
                                        const GrPaint& paint,
                                        const SkPaint& skPaint,
                                        size_t textByteLength,
                                        RenderMode renderMode,
                                        const SkMatrix& viewMatrix,
                                        const SkIRect& regionClipBounds) {
    fClip = clip;

    fRenderTarget.reset(SkRef(rt));

    fRegionClipBounds = regionClipBounds;
    fClip.getConservativeBounds(fRenderTarget->width(), fRenderTarget->height(), &fClipRect);

    fPaint = paint;
    fSkPaint = skPaint;

    fContextInitialMatrix = viewMatrix;
    fViewMatrix = viewMatrix;
    fLocalMatrix = SkMatrix::I();

    const bool otherBackendsWillDrawAsPaths =
        SkDraw::ShouldDrawTextAsPaths(skPaint, fContextInitialMatrix);

    fUsingDeviceSpaceGlyphs = !otherBackendsWillDrawAsPaths &&
                              kMaxAccuracy_RenderMode == renderMode &&
                              SkToBool(fContextInitialMatrix.getType() &
                                       (SkMatrix::kScale_Mask | SkMatrix::kAffine_Mask));

    if (fUsingDeviceSpaceGlyphs) {
        // SkDraw::ShouldDrawTextAsPaths takes care of perspective transforms.
        SkASSERT(!fContextInitialMatrix.hasPerspective());

        // The whole shape (including stroke) will be baked into the glyph outlines. Make
        // NVPR just fill the baked shapes.
        fStroke = GrStrokeInfo(SkStrokeRec::kFill_InitStyle);

        fTextRatio = fTextInverseRatio = 1.0f;

        // Glyphs loaded by GPU path rendering have an inverted y-direction.
        SkMatrix m;
        m.setScale(1, -1);
        fViewMatrix = m;

        // Post-flip the initial matrix so we're left with just the flip after
        // the paint preConcats the inverse.
        m = fContextInitialMatrix;
        m.postScale(1, -1);
        if (!m.invert(&fLocalMatrix)) {
            SkDebugf("Not invertible!\n");
            return;
        }

        fGlyphCache = fSkPaint.detachCache(&fSurfaceProps, &fContextInitialMatrix,
                                           true /*ignoreGamma*/);
        fGlyphs = get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
                                &fGlyphCache->getDescriptor(), fStroke);
    } else {
        // Don't bake strokes into the glyph outlines. We will stroke the glyphs
        // using the GPU instead. This is the fast path.
        fStroke = GrStrokeInfo(fSkPaint);
        fSkPaint.setStyle(SkPaint::kFill_Style);

        if (fStroke.isHairlineStyle()) {
            // Approximate hairline stroke.
            SkScalar strokeWidth = SK_Scalar1 /
                (SkVector::Make(fContextInitialMatrix.getScaleX(),
                                fContextInitialMatrix.getSkewY()).length());
            fStroke.setStrokeStyle(strokeWidth, false /*strokeAndFill*/);

        } else if (fSkPaint.isFakeBoldText() &&
#ifdef SK_USE_FREETYPE_EMBOLDEN
                   kMaxPerformance_RenderMode == renderMode &&
#endif
                   SkStrokeRec::kStroke_Style != fStroke.getStyle()) {

            // Instead of baking fake bold into the glyph outlines, do it with the GPU stroke.
            SkScalar fakeBoldScale = SkScalarInterpFunc(fSkPaint.getTextSize(),
                                                        kStdFakeBoldInterpKeys,
                                                        kStdFakeBoldInterpValues,
                                                        kStdFakeBoldInterpLength);
            SkScalar extra = SkScalarMul(fSkPaint.getTextSize(), fakeBoldScale);
            fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extra : extra,
                                   true /*strokeAndFill*/);

            fSkPaint.setFakeBoldText(false);
        }

        bool canUseRawPaths;
        if (!fStroke.isDashed() && (otherBackendsWillDrawAsPaths ||
                                    kMaxPerformance_RenderMode == renderMode)) {
            // We can draw the glyphs from canonically sized paths.
            fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
            fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.getTextSize();

            // Compensate for the glyphs being scaled by fTextRatio.
            if (!fStroke.isFillStyle()) {
                fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio,
                                       SkStrokeRec::kStrokeAndFill_Style == fStroke.getStyle());
            }

            fSkPaint.setLinearText(true);
            fSkPaint.setLCDRenderText(false);
            fSkPaint.setAutohinted(false);
            fSkPaint.setHinting(SkPaint::kNo_Hinting);
            fSkPaint.setSubpixelText(true);
            fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));

            canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() &&
                             0 == fSkPaint.getTextSkewX() &&
                             !fSkPaint.isFakeBoldText() &&
                             !fSkPaint.isVerticalText();
        } else {
            fTextRatio = fTextInverseRatio = 1.0f;
            canUseRawPaths = false;
        }

        SkMatrix textMatrix;
        // Glyphs loaded by GPU path rendering have an inverted y-direction.
        textMatrix.setScale(fTextRatio, -fTextRatio);
        fViewMatrix.preConcat(textMatrix);
        fLocalMatrix = textMatrix;

        fGlyphCache = fSkPaint.detachCache(&fSurfaceProps, nullptr, true /*ignoreGamma*/);
        fGlyphs = canUseRawPaths ?
                      get_gr_glyphs(fContext, fSkPaint.getTypeface(), nullptr, fStroke) :
                      get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
                                    &fGlyphCache->getDescriptor(), fStroke);
    }

}
 virtual void begin(const SkIRect& uvBounds, SkPath* )
 {
     fUVBounds.set(SkIntToScalar(uvBounds.fLeft), SkIntToScalar(uvBounds.fTop),
         SkIntToScalar(uvBounds.fRight), SkIntToScalar(uvBounds.fBottom));
 }
void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
                       const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
                       const SkPaint* paint, SkRegion** outRegion) {
    if (canvas && canvas->quickReject(bounds)) {
        return;
    }

    SkPaint defaultPaint;
    if (NULL == paint) {
        // matches default dither in NinePatchDrawable.java.
        defaultPaint.setDither(true);
        paint = &defaultPaint;
    }
   
    const int32_t* xDivs = chunk.getXDivs();
    const int32_t* yDivs = chunk.getYDivs();
    // if our SkCanvas were back by GL we should enable this and draw this as
    // a mesh, which will be faster in most cases.
    if ((false)) {
        SkNinePatch::DrawMesh(canvas, bounds, bitmap,
                              xDivs, chunk.numXDivs,
                              yDivs, chunk.numYDivs,
                              paint);
        return;
    }

    if (kUseTrace) {
        gTrace = true;
    }

    SkASSERT(canvas || outRegion);

    if (kUseTrace) {
        if (canvas) {
            const SkMatrix& m = canvas->getTotalMatrix();
            ALOGV("ninepatch [%g %g %g] [%g %g %g]\n",
                    SkScalarToFloat(m[0]), SkScalarToFloat(m[1]), SkScalarToFloat(m[2]),
                    SkScalarToFloat(m[3]), SkScalarToFloat(m[4]), SkScalarToFloat(m[5]));
        }

        ALOGV("======== ninepatch bounds [%g %g]\n", SkScalarToFloat(bounds.width()),
                SkScalarToFloat(bounds.height()));
        ALOGV("======== ninepatch paint bm [%d,%d]\n", bitmap.width(), bitmap.height());
        ALOGV("======== ninepatch xDivs [%d,%d]\n", xDivs[0], xDivs[1]);
        ALOGV("======== ninepatch yDivs [%d,%d]\n", yDivs[0], yDivs[1]);
    }

    if (bounds.isEmpty() ||
        bitmap.width() == 0 || bitmap.height() == 0 ||
        (paint && paint->getXfermode() == NULL && paint->getAlpha() == 0))
    {
        if (kUseTrace) {
            ALOGV("======== abort ninepatch draw\n");
        }
        return;
    }
    
    // should try a quick-reject test before calling lockPixels 

    SkAutoLockPixels alp(bitmap);
    // after the lock, it is valid to check getPixels()
    if (bitmap.getPixels() == NULL)
        return;

    const bool hasXfer = paint->getXfermode() != NULL;
    SkRect      dst;
    SkIRect     src;

    const int32_t x0 = xDivs[0];
    const int32_t y0 = yDivs[0];
    const SkColor initColor = ((SkPaint*)paint)->getColor();
    const uint8_t numXDivs = chunk.numXDivs;
    const uint8_t numYDivs = chunk.numYDivs;
    int i;
    int j;
    int colorIndex = 0;
    uint32_t color;
    bool xIsStretchable;
    const bool initialXIsStretchable =  (x0 == 0);
    bool yIsStretchable = (y0 == 0);
    const int bitmapWidth = bitmap.width();
    const int bitmapHeight = bitmap.height();

    // Number of bytes needed for dstRights array.
    // Need to cast numXDivs to a larger type to avoid overflow.
    const size_t dstBytes = ((size_t) numXDivs + 1) * sizeof(SkScalar);
    SkScalar* dstRights = (SkScalar*) alloca(dstBytes);
    bool dstRightsHaveBeenCached = false;

    int numStretchyXPixelsRemaining = 0;
    for (i = 0; i < numXDivs; i += 2) {
        numStretchyXPixelsRemaining += xDivs[i + 1] - xDivs[i];
    }
    int numFixedXPixelsRemaining = bitmapWidth - numStretchyXPixelsRemaining;
    int numStretchyYPixelsRemaining = 0;
    for (i = 0; i < numYDivs; i += 2) {
        numStretchyYPixelsRemaining += yDivs[i + 1] - yDivs[i];
    }
    int numFixedYPixelsRemaining = bitmapHeight - numStretchyYPixelsRemaining;

    if (kUseTrace) {
        ALOGV("NinePatch [%d %d] bounds [%g %g %g %g] divs [%d %d]\n",
                bitmap.width(), bitmap.height(),
                SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
                SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height()),
                numXDivs, numYDivs);
    }

    src.fTop = 0;
    dst.fTop = bounds.fTop;
    // The first row always starts with the top being at y=0 and the bottom
    // being either yDivs[1] (if yDivs[0]=0) or yDivs[0].  In the former case
    // the first row is stretchable along the Y axis, otherwise it is fixed.
    // The last row always ends with the bottom being bitmap.height and the top
    // being either yDivs[numYDivs-2] (if yDivs[numYDivs-1]=bitmap.height) or
    // yDivs[numYDivs-1]. In the former case the last row is stretchable along
    // the Y axis, otherwise it is fixed.
    //
    // The first and last columns are similarly treated with respect to the X
    // axis.
    //
    // The above is to help explain some of the special casing that goes on the
    // code below.

    // The initial yDiv and whether the first row is considered stretchable or
    // not depends on whether yDiv[0] was zero or not.
    for (j = yIsStretchable ? 1 : 0;
          j <= numYDivs && src.fTop < bitmapHeight;
          j++, yIsStretchable = !yIsStretchable) {
        src.fLeft = 0;
        dst.fLeft = bounds.fLeft;
        if (j == numYDivs) {
            src.fBottom = bitmapHeight;
            dst.fBottom = bounds.fBottom;
        } else {
            src.fBottom = yDivs[j];
            const int srcYSize = src.fBottom - src.fTop;
            if (yIsStretchable) {
                dst.fBottom = dst.fTop + calculateStretch(bounds.fBottom, dst.fTop,
                                                          srcYSize,
                                                          numStretchyYPixelsRemaining,
                                                          numFixedYPixelsRemaining);
                numStretchyYPixelsRemaining -= srcYSize;
            } else {
                dst.fBottom = dst.fTop + SkIntToScalar(srcYSize);
                numFixedYPixelsRemaining -= srcYSize;
            }
        }

        xIsStretchable = initialXIsStretchable;
        // The initial xDiv and whether the first column is considered
        // stretchable or not depends on whether xDiv[0] was zero or not.
        const uint32_t* colors = chunk.getColors();
        for (i = xIsStretchable ? 1 : 0;
              i <= numXDivs && src.fLeft < bitmapWidth;
              i++, xIsStretchable = !xIsStretchable) {
            color = colors[colorIndex++];
            if (i == numXDivs) {
                src.fRight = bitmapWidth;
                dst.fRight = bounds.fRight;
            } else {
                src.fRight = xDivs[i];
                if (dstRightsHaveBeenCached) {
                    dst.fRight = dstRights[i];
                } else {
                    const int srcXSize = src.fRight - src.fLeft;
                    if (xIsStretchable) {
                        dst.fRight = dst.fLeft + calculateStretch(bounds.fRight, dst.fLeft,
                                                                  srcXSize,
                                                                  numStretchyXPixelsRemaining,
                                                                  numFixedXPixelsRemaining);
                        numStretchyXPixelsRemaining -= srcXSize;
                    } else {
                        dst.fRight = dst.fLeft + SkIntToScalar(srcXSize);
                        numFixedXPixelsRemaining -= srcXSize;
                    }
                    dstRights[i] = dst.fRight;
                }
            }
            // If this horizontal patch is too small to be displayed, leave
            // the destination left edge where it is and go on to the next patch
            // in the source.
            if (src.fLeft >= src.fRight) {
                src.fLeft = src.fRight;
                continue;
            }
            // Make sure that we actually have room to draw any bits
            if (dst.fRight <= dst.fLeft || dst.fBottom <= dst.fTop) {
                goto nextDiv;
            }
            // If this patch is transparent, skip and don't draw.
            if (color == android::Res_png_9patch::TRANSPARENT_COLOR && !hasXfer) {
                if (outRegion) {
                    if (*outRegion == NULL) {
                        *outRegion = new SkRegion();
                    }
                    SkIRect idst;
                    dst.round(&idst);
                    //ALOGI("Adding trans rect: (%d,%d)-(%d,%d)\n",
                    //     idst.fLeft, idst.fTop, idst.fRight, idst.fBottom);
                    (*outRegion)->op(idst, SkRegion::kUnion_Op);
                }
                goto nextDiv;
            }
            if (canvas) {
                if (kUseTrace) {
                    ALOGV("-- src [%d %d %d %d] dst [%g %g %g %g]\n",
                            src.fLeft, src.fTop, src.width(), src.height(),
                            SkScalarToFloat(dst.fLeft), SkScalarToFloat(dst.fTop),
                            SkScalarToFloat(dst.width()), SkScalarToFloat(dst.height()));
                    if (2 == src.width() && SkIntToScalar(5) == dst.width()) {
                        ALOGV("--- skip patch\n");
                    }
                }
                drawStretchyPatch(canvas, src, dst, bitmap, *paint, initColor,
                                  color, hasXfer);
            }

nextDiv:
            src.fLeft = src.fRight;
            dst.fLeft = dst.fRight;
        }
        src.fTop = src.fBottom;
        dst.fTop = dst.fBottom;
        dstRightsHaveBeenCached = true;
    }
}
示例#15
0
 void onOnceBeforeDraw() override {
     this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
     fCirclePath.addCircle(SkIntToScalar(20), SkIntToScalar(20), SkIntToScalar(10) );
     fRect.set(SkIntToScalar(10), SkIntToScalar(10),
               SkIntToScalar(30), SkIntToScalar(30));
 }
示例#16
0
static SkPath testPath() {
    SkPath path;
    path.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
                                  SkIntToScalar(2), SkIntToScalar(1)));
    return path;
}
示例#17
0
    // Only called once. Could be part of the constructor.
    void init(SkScalar seed)
    {
        static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize));

        // According to the SVG spec, we must truncate (not round) the seed value.
        fSeed = SkScalarTruncToInt(seed);
        // The seed value clamp to the range [1, kRandMaximum - 1].
        if (fSeed <= 0) {
            fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
        }
        if (fSeed > kRandMaximum - 1) {
            fSeed = kRandMaximum - 1;
        }
        for (int channel = 0; channel < 4; ++channel) {
            for (int i = 0; i < kBlockSize; ++i) {
                fLatticeSelector[i] = i;
                fNoise[channel][i][0] = (random() % (2 * kBlockSize));
                fNoise[channel][i][1] = (random() % (2 * kBlockSize));
            }
        }
        for (int i = kBlockSize - 1; i > 0; --i) {
            int k = fLatticeSelector[i];
            int j = random() % kBlockSize;
            SkASSERT(j >= 0);
            SkASSERT(j < kBlockSize);
            fLatticeSelector[i] = fLatticeSelector[j];
            fLatticeSelector[j] = k;
        }

        // Perform the permutations now
        {
            // Copy noise data
            uint16_t noise[4][kBlockSize][2];
            for (int i = 0; i < kBlockSize; ++i) {
                for (int channel = 0; channel < 4; ++channel) {
                    for (int j = 0; j < 2; ++j) {
                        noise[channel][i][j] = fNoise[channel][i][j];
                    }
                }
            }
            // Do permutations on noise data
            for (int i = 0; i < kBlockSize; ++i) {
                for (int channel = 0; channel < 4; ++channel) {
                    for (int j = 0; j < 2; ++j) {
                        fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
                    }
                }
            }
        }

        // Half of the largest possible value for 16 bit unsigned int
        static const SkScalar gHalfMax16bits = 32767.5f;

        // Compute gradients from permutated noise data
        for (int channel = 0; channel < 4; ++channel) {
            for (int i = 0; i < kBlockSize; ++i) {
                fGradient[channel][i] = SkPoint::Make(
                    SkScalarMul(SkIntToScalar(fNoise[channel][i][0] - kBlockSize),
                                gInvBlockSizef),
                    SkScalarMul(SkIntToScalar(fNoise[channel][i][1] - kBlockSize),
                                gInvBlockSizef));
                fGradient[channel][i].normalize();
                // Put the normalized gradient back into the noise data
                fNoise[channel][i][0] = SkScalarRoundToInt(SkScalarMul(
                    fGradient[channel][i].fX + SK_Scalar1, gHalfMax16bits));
                fNoise[channel][i][1] = SkScalarRoundToInt(SkScalarMul(
                    fGradient[channel][i].fY + SK_Scalar1, gHalfMax16bits));
            }
        }
    }
示例#18
0
static void testOpLoopsMain(PathOpsThreadState* data) {
#if DEBUG_SHOW_TEST_NAME
    strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
#endif
    SkASSERT(data);
    PathOpsThreadState& state = *data;
    SkString pathStr;
    for (int a = 0 ; a < 6; ++a) {
        for (int b = a + 1 ; b < 7; ++b) {
            for (int c = 0 ; c < 6; ++c) {
                for (int d = c + 1 ; d < 7; ++d) {
        // define 4 points that form two lines that often cross; one line is (a, b) (c, d)
        SkVector v = {SkIntToScalar(a - c), SkIntToScalar(b - d)};
        SkPoint midA = { SkIntToScalar(a * state.fA + c * (6 - state.fA)) / 6,
                         SkIntToScalar(b * state.fA + d * (6 - state.fA)) / 6 };
        SkPoint midB = { SkIntToScalar(a * state.fB + c * (6 - state.fB)) / 6,
                         SkIntToScalar(b * state.fB + d * (6 - state.fB)) / 6 };
        SkPoint endC = { midA.fX + v.fY * state.fC / 3,
                          midA.fY + v.fX * state.fC / 3 };
        SkPoint endD = { midB.fX - v.fY * state.fD / 3,
                          midB.fY + v.fX * state.fD / 3 };
        SkPath pathA, pathB;
        pathA.moveTo(SkIntToScalar(a), SkIntToScalar(b));
        pathA.cubicTo(SkIntToScalar(c), SkIntToScalar(d), endC.fX, endC.fY, endD.fX, endD.fY);
        pathA.close();
        pathB.moveTo(SkIntToScalar(c), SkIntToScalar(d));
        pathB.cubicTo(endC.fX, endC.fY, endD.fX, endD.fY, SkIntToScalar(a), SkIntToScalar(b));
        pathB.close();
//        SkDebugf("%s\n", pathStr);
        if (state.fReporter->verbose()) {
            pathStr.printf("static void loop%d(skiatest::Reporter* reporter,"
                    " const char* filename) {\n", loopNo);
            pathStr.appendf("    SkPath path, pathB;\n");
            pathStr.appendf("    path.moveTo(%d,%d);\n", a, b);
            pathStr.appendf("    path.cubicTo(%d,%d, ", c, d);
            add_point(&pathStr, endC.fX, endC.fY);
            pathStr.appendf(", ");
            add_point(&pathStr, endD.fX, endD.fY);
            pathStr.appendf(");\n");
            pathStr.appendf("    path.close();\n");
            pathStr.appendf("    pathB.moveTo(%d,%d);\n", c, d);
            pathStr.appendf("    pathB.cubicTo(");
            add_point(&pathStr, endC.fX, endC.fY);
            pathStr.appendf(", ");
            add_point(&pathStr, endD.fX, endD.fY);
            pathStr.appendf(", %d,%d);\n", a, b);
            pathStr.appendf("    pathB.close();\n");
            pathStr.appendf("    testPathOp(reporter, path, pathB, kIntersect_SkPathOp,"
                    " filename);\n");
            pathStr.appendf("}\n");
            state.outputProgress(pathStr.c_str(), kIntersect_SkPathOp);
        }
        SkString testName;
        testName.printf("thread_loops%d", ++gLoopsTestNo);
        testPathOp(state.fReporter, pathA, pathB, kIntersect_SkPathOp, testName.c_str());
        if (PathOpsDebug::gCheckForDuplicateNames) return;
                }
            }
        }
    }
}
示例#19
0
static sk_sp<SkImageFilter> make_image_filter(bool canBeNull) {
    sk_sp<SkImageFilter> filter;

    // Add a 1 in 3 chance to get a nullptr input
    if (canBeNull && (R(3) == 1)) {
        return filter;
    }

    enum { ALPHA_THRESHOLD, MERGE, COLOR, LUT3D, BLUR, MAGNIFIER,
           DOWN_SAMPLE, XFERMODE, OFFSET, MATRIX, MATRIX_CONVOLUTION, COMPOSE,
           DISTANT_LIGHT, POINT_LIGHT, SPOT_LIGHT, NOISE, DROP_SHADOW,
           MORPHOLOGY, BITMAP, DISPLACE, TILE, PICTURE, PAINT, NUM_FILTERS };

    switch (R(NUM_FILTERS)) {
    case ALPHA_THRESHOLD:
        filter = SkAlphaThresholdFilter::Make(make_region(),
                                              make_scalar(),
                                              make_scalar(),
                                              make_image_filter());
        break;
    case MERGE:
        filter = SkMergeImageFilter::Make(make_image_filter(),
                                          make_image_filter(),
                                          make_xfermode());
        break;
    case COLOR: {
        sk_sp<SkColorFilter> cf(make_color_filter());
        filter = cf ? SkColorFilterImageFilter::Make(std::move(cf), make_image_filter())
                    : nullptr;
        break;
    }
    case LUT3D: {
        int cubeDimension;
        sk_sp<SkData> lut3D(make_3Dlut(&cubeDimension, (R(2) == 1), (R(2) == 1), (R(2) == 1)));
        sk_sp<SkColorFilter> cf(SkColorCubeFilter::Make(std::move(lut3D), cubeDimension));
        filter = cf ? SkColorFilterImageFilter::Make(std::move(cf), make_image_filter())
                    : nullptr;
        break;
    }
    case BLUR:
        filter = SkBlurImageFilter::Make(make_scalar(true),
                                         make_scalar(true),
                                         make_image_filter());
        break;
    case MAGNIFIER:
        filter = SkMagnifierImageFilter::Make(make_rect(),
                                              make_scalar(true),
                                              make_image_filter());
        break;
    case DOWN_SAMPLE:
        filter = SkDownSampleImageFilter::Make(make_scalar(), make_image_filter());
        break;
    case XFERMODE:
        filter = SkXfermodeImageFilter::Make(SkXfermode::Make(make_xfermode()),
                                             make_image_filter(),
                                             make_image_filter(),
                                             nullptr);
        break;
    case OFFSET:
        filter = SkOffsetImageFilter::Make(make_scalar(), make_scalar(), make_image_filter());
        break;
    case MATRIX:
        filter = SkImageFilter::MakeMatrixFilter(make_matrix(),
                                                 (SkFilterQuality)R(4),
                                                 make_image_filter());
        break;
    case MATRIX_CONVOLUTION: {
        SkImageFilter::CropRect cropR(SkRect::MakeWH(SkIntToScalar(kBitmapSize),
                                                     SkIntToScalar(kBitmapSize)));
        SkISize size = SkISize::Make(R(10)+1, R(10)+1);
        int arraySize = size.width() * size.height();
        SkTArray<SkScalar> kernel(arraySize);
        for (int i = 0; i < arraySize; ++i) {
            kernel.push_back() = make_scalar();
        }
        SkIPoint kernelOffset = SkIPoint::Make(R(SkIntToScalar(size.width())),
                                               R(SkIntToScalar(size.height())));

        filter = SkMatrixConvolutionImageFilter::Make(size,
                                                      kernel.begin(),
                                                      make_scalar(),
                                                      make_scalar(),
                                                      kernelOffset,
                                                      (SkMatrixConvolutionImageFilter::TileMode)R(3),
                                                      R(2) == 1,
                                                      make_image_filter(),
                                                      &cropR);
        break;
    }
    case COMPOSE:
        filter = SkComposeImageFilter::Make(make_image_filter(), make_image_filter());
        break;
    case DISTANT_LIGHT:
        filter = (R(2) == 1)
                 ? SkLightingImageFilter::MakeDistantLitDiffuse(make_point(), make_color(),
                                                                make_scalar(), make_scalar(),
                                                                make_image_filter())
                 : SkLightingImageFilter::MakeDistantLitSpecular(make_point(), make_color(),
                                                                 make_scalar(), make_scalar(),
                                                                 SkIntToScalar(R(10)),
                                                                 make_image_filter());
        break;
    case POINT_LIGHT:
        filter = (R(2) == 1)
                 ? SkLightingImageFilter::MakePointLitDiffuse(make_point(), make_color(),
                                                              make_scalar(), make_scalar(),
                                                              make_image_filter())
                 : SkLightingImageFilter::MakePointLitSpecular(make_point(), make_color(),
                                                               make_scalar(), make_scalar(),
                                                               SkIntToScalar(R(10)),
                                                               make_image_filter());
        break;
    case SPOT_LIGHT:
        filter = (R(2) == 1)
                 ? SkLightingImageFilter::MakeSpotLitDiffuse(SkPoint3::Make(0, 0, 0),
                                                             make_point(), make_scalar(),
                                                             make_scalar(), make_color(),
                                                             make_scalar(), make_scalar(),
                                                             make_image_filter())
                 : SkLightingImageFilter::MakeSpotLitSpecular(SkPoint3::Make(0, 0, 0),
                                                              make_point(), make_scalar(),
                                                              make_scalar(), make_color(),
                                                              make_scalar(), make_scalar(),
                                                              SkIntToScalar(R(10)),
                                                              make_image_filter());
        break;
    case NOISE: {
        sk_sp<SkShader> shader((R(2) == 1)
                ? SkPerlinNoiseShader::MakeFractalNoise(make_scalar(true), make_scalar(true),
                                                        R(10.0f), make_scalar())
                : SkPerlinNoiseShader::MakeTurbulence(make_scalar(true), make_scalar(true),
                                                      R(10.0f), make_scalar()));
        SkPaint paint;
        paint.setShader(shader);
        SkImageFilter::CropRect cropR(SkRect::MakeWH(SkIntToScalar(kBitmapSize),
                                                     SkIntToScalar(kBitmapSize)));
        filter = SkPaintImageFilter::Make(paint, &cropR);
        break;
    }
    case DROP_SHADOW:
        filter = SkDropShadowImageFilter::Make(make_scalar(),
                                               make_scalar(),
                                               make_scalar(true),
                                               make_scalar(true),
                                               make_color(),
                                               make_shadow_mode(),
                                               make_image_filter(),
                                               nullptr);
        break;
    case MORPHOLOGY:
        if (R(2) == 1) {
            filter = SkDilateImageFilter::Make(R(static_cast<float>(kBitmapSize)),
                                               R(static_cast<float>(kBitmapSize)),
                                               make_image_filter());
        } else {
            filter = SkErodeImageFilter::Make(R(static_cast<float>(kBitmapSize)),
                                              R(static_cast<float>(kBitmapSize)),
                                              make_image_filter());
        }
        break;
    case BITMAP: {
        sk_sp<SkImage> image(SkImage::MakeFromBitmap(make_bitmap()));
        if (R(2) == 1) {
            filter = SkImageSource::Make(std::move(image),
                                         make_rect(),
                                         make_rect(),
                                         kHigh_SkFilterQuality);
        } else {
            filter = SkImageSource::Make(std::move(image));
        }
        break;
    }
    case DISPLACE:
        filter = SkDisplacementMapEffect::Make(make_channel_selector_type(),
                                               make_channel_selector_type(),
                                               make_scalar(),
                                               make_image_filter(false),
                                               make_image_filter());
        break;
    case TILE:
        filter = SkTileImageFilter::Make(make_rect(), make_rect(), make_image_filter(false));
        break;
    case PICTURE: {
        SkRTreeFactory factory;
        SkPictureRecorder recorder;
        SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(kBitmapSize),
                                                            SkIntToScalar(kBitmapSize),
                                                            &factory, 0);
        drawSomething(recordingCanvas);
        sk_sp<SkPicture> pict(recorder.finishRecordingAsPicture());
        filter = SkPictureImageFilter::Make(pict, make_rect());
        break;
    }
    case PAINT: {
        SkImageFilter::CropRect cropR(make_rect());
        filter = SkPaintImageFilter::Make(make_paint(), &cropR);
        break;
    }
    default:
        break;
    }
    return (filter || canBeNull) ? filter : make_image_filter(canBeNull);
}
static GrTexture* copy_on_gpu(GrTexture* inputTexture, const SkIRect* subset,
                              const CopyParams& copyParams) {
    SkASSERT(!subset || !subset->isEmpty());
    GrContext* context = inputTexture->getContext();
    SkASSERT(context);
    const GrCaps* caps = context->caps();

    // Either it's a cache miss or the original wasn't cached to begin with.
    GrSurfaceDesc rtDesc = inputTexture->desc();
    rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag;
    rtDesc.fWidth = copyParams.fWidth;
    rtDesc.fHeight = copyParams.fHeight;
    rtDesc.fConfig = GrMakePixelConfigUncompressed(rtDesc.fConfig);

    // If the config isn't renderable try converting to either A8 or an 32 bit config. Otherwise,
    // fail.
    if (!caps->isConfigRenderable(rtDesc.fConfig, false)) {
        if (GrPixelConfigIsAlphaOnly(rtDesc.fConfig)) {
            if (caps->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
                rtDesc.fConfig = kAlpha_8_GrPixelConfig;
            } else if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
                rtDesc.fConfig = kSkia8888_GrPixelConfig;
            } else {
                return nullptr;
            }
        } else if (kRGB_GrColorComponentFlags ==
                   (kRGB_GrColorComponentFlags & GrPixelConfigComponentMask(rtDesc.fConfig))) {
            if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
                rtDesc.fConfig = kSkia8888_GrPixelConfig;
            } else {
                return nullptr;
            }
        } else {
            return nullptr;
        }
    }

    SkAutoTUnref<GrTexture> copy(context->textureProvider()->createTexture(rtDesc, true));
    if (!copy) {
        return nullptr;
    }

    // TODO: If no scaling is being performed then use copySurface.

    GrPaint paint;

    // TODO: Initializing these values for no reason cause the compiler is complaining
    SkScalar sx = 0.f;
    SkScalar sy = 0.f;
    if (subset) {
        sx = 1.f / inputTexture->width();
        sy = 1.f / inputTexture->height();
    }

    if (copyParams.fFilter != GrTextureParams::kNone_FilterMode && subset &&
        (subset->width() != copyParams.fWidth || subset->height() != copyParams.fHeight)) {
        SkRect domain;
        domain.fLeft = (subset->fLeft + 0.5f) * sx;
        domain.fTop = (subset->fTop + 0.5f)* sy;
        domain.fRight = (subset->fRight - 0.5f) * sx;
        domain.fBottom = (subset->fBottom - 0.5f) * sy;
        // This would cause us to read values from outside the subset. Surely, the caller knows
        // better!
        SkASSERT(copyParams.fFilter != GrTextureParams::kMipMap_FilterMode);
        paint.addColorFragmentProcessor(
            GrTextureDomainEffect::Create(inputTexture, SkMatrix::I(), domain,
                                          GrTextureDomain::kClamp_Mode,
                                          copyParams.fFilter))->unref();
    } else {
        GrTextureParams params(SkShader::kClamp_TileMode, copyParams.fFilter);
        paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params);
    }
    paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);

    SkRect localRect;
    if (subset) {
        localRect = SkRect::Make(*subset);
        localRect.fLeft *= sx;
        localRect.fTop *= sy;
        localRect.fRight *= sx;
        localRect.fBottom *= sy;
    } else {
        localRect = SkRect::MakeWH(1.f, 1.f);
    }

    SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(copy->asRenderTarget()));
    if (!drawContext) {
        return nullptr;
    }

    SkRect dstRect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight));
    drawContext->fillRectToRect(GrClip::WideOpen(), paint, SkMatrix::I(), dstRect, localRect);
    return copy.detach();
}
SkImageFilter* SkiaImageFilterBuilder::build(const FilterOperations& operations)
{
    SkAutoTUnref<SkImageFilter> filter;
    SkScalar matrix[20];
    for (size_t i = 0; i < operations.size(); ++i) {
        const FilterOperation& op = *operations.at(i);
        switch (op.getOperationType()) {
        case FilterOperation::REFERENCE: {
            FilterEffect* filterEffect = static_cast<const ReferenceFilterOperation*>(&op)->filterEffect();
            // FIXME: hook up parent filter to image source
            filter.reset(SkiaImageFilterBuilder::build(filterEffect));
            break;
        }
        case FilterOperation::GRAYSCALE: {
            float amount = static_cast<const BasicColorMatrixFilterOperation*>(&op)->amount();
            getGrayscaleMatrix(1 - amount, matrix);
            filter.reset(createMatrixImageFilter(matrix, filter));
            break;
        }
        case FilterOperation::SEPIA: {
            float amount = static_cast<const BasicColorMatrixFilterOperation*>(&op)->amount();
            getSepiaMatrix(1 - amount, matrix);
            filter.reset(createMatrixImageFilter(matrix, filter));
            break;
        }
        case FilterOperation::SATURATE: {
            float amount = static_cast<const BasicColorMatrixFilterOperation*>(&op)->amount();
            getSaturateMatrix(amount, matrix);
            filter.reset(createMatrixImageFilter(matrix, filter));
            break;
        }
        case FilterOperation::HUE_ROTATE: {
            float amount = static_cast<const BasicColorMatrixFilterOperation*>(&op)->amount();
            getHueRotateMatrix(amount, matrix);
            filter.reset(createMatrixImageFilter(matrix, filter));
            break;
        }
        case FilterOperation::INVERT: {
            float amount = static_cast<const BasicComponentTransferFilterOperation*>(&op)->amount();
            getInvertMatrix(amount, matrix);
            filter.reset(createMatrixImageFilter(matrix, filter));
            break;
        }
        case FilterOperation::OPACITY: {
            float amount = static_cast<const BasicComponentTransferFilterOperation*>(&op)->amount();
            getOpacityMatrix(amount, matrix);
            filter.reset(createMatrixImageFilter(matrix, filter));
            break;
        }
        case FilterOperation::BRIGHTNESS: {
            float amount = static_cast<const BasicComponentTransferFilterOperation*>(&op)->amount();
            getBrightnessMatrix(amount, matrix);
            filter.reset(createMatrixImageFilter(matrix, filter));
            break;
        }
        case FilterOperation::CONTRAST: {
            float amount = static_cast<const BasicComponentTransferFilterOperation*>(&op)->amount();
            getContrastMatrix(amount, matrix);
            filter.reset(createMatrixImageFilter(matrix, filter));
            break;
        }
        case FilterOperation::BLUR: {
            float pixelRadius = static_cast<const BlurFilterOperation*>(&op)->stdDeviation().getFloatValue();
            filter.reset(new SkBlurImageFilter(pixelRadius, pixelRadius, filter));
            break;
        }
        case FilterOperation::DROP_SHADOW: {
            const DropShadowFilterOperation* drop = static_cast<const DropShadowFilterOperation*>(&op);
            filter.reset(new DropShadowImageFilter(SkIntToScalar(drop->x()), SkIntToScalar(drop->y()), SkIntToScalar(drop->stdDeviation()), drop->color().rgb(), filter));
            break;
        }
        case FilterOperation::VALIDATED_CUSTOM:
        case FilterOperation::CUSTOM:
            // Not supported.
        case FilterOperation::PASSTHROUGH:
        case FilterOperation::NONE:
            break;
        }
    }
    return filter.detach();
}
示例#22
0
static void generateMask(const SkMask& mask, const SkPath& path,
                         const SkMaskGamma::PreBlend& maskPreBlend) {
    SkPaint paint;

    int srcW = mask.fBounds.width();
    int srcH = mask.fBounds.height();
    int dstW = srcW;
    int dstH = srcH;
    int dstRB = mask.fRowBytes;

    SkMatrix matrix;
    matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
                        -SkIntToScalar(mask.fBounds.fTop));

    paint.setAntiAlias(SkMask::kBW_Format != mask.fFormat);
    switch (mask.fFormat) {
        case SkMask::kBW_Format:
            dstRB = 0;  // signals we need a copy
            break;
        case SkMask::kA8_Format:
            break;
        case SkMask::kLCD16_Format:
        case SkMask::kLCD32_Format:
            // TODO: trigger off LCD orientation
            dstW = 4*dstW - 8;
            matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1),
                                -SkIntToScalar(mask.fBounds.fTop));
            matrix.postScale(SkIntToScalar(4), SK_Scalar1);
            dstRB = 0;  // signals we need a copy
            break;
        default:
            SkDEBUGFAIL("unexpected mask format");
    }

    SkRasterClip clip;
    clip.setRect(SkIRect::MakeWH(dstW, dstH));

    const SkImageInfo info = SkImageInfo::MakeA8(dstW, dstH);
    SkBitmap bm;

    if (0 == dstRB) {
        if (!bm.tryAllocPixels(info)) {
            // can't allocate offscreen, so empty the mask and return
            sk_bzero(mask.fImage, mask.computeImageSize());
            return;
        }
    } else {
        bm.installPixels(info, mask.fImage, dstRB);
    }
    sk_bzero(bm.getPixels(), bm.getSafeSize());

    SkDraw  draw;
    draw.fRC    = &clip;
    draw.fClip  = &clip.bwRgn();
    draw.fMatrix = &matrix;
    draw.fBitmap = &bm;
    draw.drawPath(path, paint);

    switch (mask.fFormat) {
        case SkMask::kBW_Format:
            packA8ToA1(mask, bm.getAddr8(0, 0), bm.rowBytes());
            break;
        case SkMask::kA8_Format:
            if (maskPreBlend.isApplicable()) {
                applyLUTToA8Mask(mask, maskPreBlend.fG);
            }
            break;
        case SkMask::kLCD16_Format:
            if (maskPreBlend.isApplicable()) {
                pack4xHToLCD16<true>(bm, mask, maskPreBlend);
            } else {
                pack4xHToLCD16<false>(bm, mask, maskPreBlend);
            }
            break;
        case SkMask::kLCD32_Format:
            if (maskPreBlend.isApplicable()) {
                pack4xHToLCD32<true>(bm, mask, maskPreBlend);
            } else {
                pack4xHToLCD32<false>(bm, mask, maskPreBlend);
            }
            break;
        default:
            break;
    }
}
示例#23
0
    virtual void onDraw(SkCanvas* canvas) {
        SkBlurMaskFilter::BlurStyle NONE = SkBlurMaskFilter::BlurStyle(-999);
        static const struct {
            SkBlurMaskFilter::BlurStyle fStyle;
            int                         fCx, fCy;
        } gRecs[] = {
            { NONE,                                 0,  0 },
            { SkBlurMaskFilter::kInner_BlurStyle,  -1,  0 },
            { SkBlurMaskFilter::kNormal_BlurStyle,  0,  1 },
            { SkBlurMaskFilter::kSolid_BlurStyle,   0, -1 },
            { SkBlurMaskFilter::kOuter_BlurStyle,   1,  0 },
        };

        SkPaint paint;
        paint.setAntiAlias(true);
        paint.setTextSize(SkIntToScalar(25));
        canvas->translate(SkIntToScalar(-40), SkIntToScalar(0));

        SkBlurMaskFilter::BlurFlags flags = SkBlurMaskFilter::kNone_BlurFlag;
        for (int j = 0; j < 2; j++) {
            canvas->save();
            paint.setColor(SK_ColorBLUE);
            for (size_t i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
                if (gRecs[i].fStyle != NONE) {
                    SkMaskFilter* mf = SkBlurMaskFilter::Create(
                            SkIntToScalar(20), gRecs[i].fStyle, flags
                    );
                    paint.setMaskFilter(mf)->unref();
                } else {
                    paint.setMaskFilter(NULL);
                }
                canvas->drawCircle(SkIntToScalar(200 + gRecs[i].fCx*100)
                                   , SkIntToScalar(200 + gRecs[i].fCy*100)
                                   , SkIntToScalar(50)
                                   , paint);
            }
            // draw text
            {
                SkMaskFilter* mf = SkBlurMaskFilter::Create(
                        SkIntToScalar(4)
                        , SkBlurMaskFilter::kNormal_BlurStyle
                        , flags
                );
                paint.setMaskFilter(mf)->unref();
                SkScalar x = SkIntToScalar(70);
                SkScalar y = SkIntToScalar(400);
                paint.setColor(SK_ColorBLACK);
                canvas->drawText("Hamburgefons Style", 18, x, y, paint);
                canvas->drawText("Hamburgefons Style", 18
                                 , x, y + SkIntToScalar(50), paint);
                paint.setMaskFilter(NULL);
                paint.setColor(SK_ColorWHITE);
                x -= SkIntToScalar(2);
                y -= SkIntToScalar(2);
                canvas->drawText("Hamburgefons Style", 18, x, y, paint);
            }
            canvas->restore();
            flags = SkBlurMaskFilter::kHighQuality_BlurFlag;
            canvas->translate(SkIntToScalar(350), SkIntToScalar(0));
        }
    }
示例#24
0
/*
 * 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 "SkTouchGesture.h"
#include "SkMatrix.h"
#include "SkTime.h"

#define DISCRETIZE_TRANSLATE_TO_AVOID_FLICKER   true

static const SkScalar MAX_FLING_SPEED = SkIntToScalar(1500);

static SkScalar pin_max_fling(SkScalar speed) {
    if (speed > MAX_FLING_SPEED) {
        speed = MAX_FLING_SPEED;
    }
    return speed;
}

static double getseconds() {
    return SkTime::GetMSecs() * 0.001;
}

// returns +1 or -1, depending on the sign of x
// returns +1 if z is zero
static SkScalar SkScalarSignNonZero(SkScalar x) {
示例#25
0
文件: shadows.cpp 项目: Arternis/skia
    virtual void onDraw(SkCanvas* canvas) {
    SkBlurDrawLooper* shadowLoopers[5];
    shadowLoopers[0] =
        SkBlurDrawLooper::Create(SK_ColorBLUE,
                                 SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(10)),
                                 SkIntToScalar(5), SkIntToScalar(10),
                                 SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
                                 SkBlurDrawLooper::kOverrideColor_BlurFlag |
                                 SkBlurDrawLooper::kHighQuality_BlurFlag);
    SkAutoUnref aurL0(shadowLoopers[0]);
    shadowLoopers[1] =
        SkBlurDrawLooper::Create(SK_ColorBLUE,
                                 SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(10)),
                                 SkIntToScalar(5), SkIntToScalar(10),
                                 SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
                                 SkBlurDrawLooper::kOverrideColor_BlurFlag);
    SkAutoUnref aurL1(shadowLoopers[1]);
    shadowLoopers[2] =
        SkBlurDrawLooper::Create(SK_ColorBLACK,
                                 SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(5)),
                                 SkIntToScalar(5),
                                 SkIntToScalar(10),
                                 SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
                                 SkBlurDrawLooper::kHighQuality_BlurFlag);
    SkAutoUnref aurL2(shadowLoopers[2]);
    shadowLoopers[3] =
        SkBlurDrawLooper::Create(0x7FFF0000,
                                 SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(5)),
                                 SkIntToScalar(-5), SkIntToScalar(-10),
                                 SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
                                 SkBlurDrawLooper::kOverrideColor_BlurFlag |
                                 SkBlurDrawLooper::kHighQuality_BlurFlag);
    SkAutoUnref aurL3(shadowLoopers[3]);
    shadowLoopers[4] =
        SkBlurDrawLooper::Create(SK_ColorBLACK, SkIntToScalar(0),
                                 SkIntToScalar(5), SkIntToScalar(5),
                                 SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
                                 SkBlurDrawLooper::kOverrideColor_BlurFlag |
                                 SkBlurDrawLooper::kHighQuality_BlurFlag);
    SkAutoUnref aurL4(shadowLoopers[4]);

    static const struct {
        SkColor fColor;
        SkScalar fStrokeWidth;
    } gRec[] = {
        { SK_ColorRED,      -SK_Scalar1 },
        { SK_ColorGREEN,    SkIntToScalar(4) },
        { SK_ColorBLUE,     SkIntToScalar(0)},
    };

    SkPaint paint;
    paint.setAntiAlias(true);
    for (size_t i = 0; i < SK_ARRAY_COUNT(shadowLoopers); ++i) {
        SkAutoCanvasRestore acr(canvas, true);

        paint.setLooper(shadowLoopers[i]);

        canvas->translate(SkIntToScalar((unsigned int)i*40), SkIntToScalar(0));
        setup(&paint, gRec[0].fColor, gRec[0].fStrokeWidth);
        canvas->drawRect(fRect, paint);

        canvas->translate(SkIntToScalar(0), SkIntToScalar(40));
        setup(&paint, gRec[1].fColor, gRec[1].fStrokeWidth);
        canvas->drawPath(fCirclePath, paint);

        canvas->translate(SkIntToScalar(0), SkIntToScalar(40));
        setup(&paint, gRec[2].fColor, gRec[2].fStrokeWidth);
        canvas->drawPath(fCirclePath, paint);
    }
}
示例#26
0
void WRasterImage::setChanged(WFlags<ChangeFlag> flags)
{
  if (flags & Clipping) {
    
    if (painter()->hasClipping()) {
      impl_->setTransform(painter()->clipPathTransform());
      SkPath clipPath;
      impl_->drawPlainPath(clipPath, painter()->clipPath());
      impl_->canvas_->clipPath(clipPath, SkRegion::kReplace_Op);
    } else {
      impl_->canvas_->restore();
      impl_->canvas_->save();
    }
    impl_->setTransform(painter()->combinedTransform());
  }

  if (flags & Transform) {
    impl_->setTransform(painter()->combinedTransform());
    flags = Pen | Brush | Font | Hints;
  }

  if (flags & Hints) {
    if (!(painter()->renderHints() & WPainter::Antialiasing)) {
      impl_->strokePaint_.setAntiAlias(false);
      impl_->fillPaint_.setAntiAlias(false);
      impl_->textPaint_.setAntiAlias(false);
    } else {
      impl_->strokePaint_.setAntiAlias(true);
      impl_->fillPaint_.setAntiAlias(true);
      impl_->textPaint_.setAntiAlias(true);
    }
  }

  if (flags & Pen) {
    const WPen& pen = painter()->pen();

    if (pen.style() != NoPen) {
      const WColor& color = pen.color();

      impl_->strokePaint_.setColor(fromWColor(color));

      WLength w = pen.width();
      impl_->strokePaint_.setStrokeWidth(SkIntToScalar(w.toPixels()));

      switch (pen.capStyle()) {
      case FlatCap:
	impl_->strokePaint_.setStrokeCap(SkPaint::kButt_Cap);
	break;
      case SquareCap:
	impl_->strokePaint_.setStrokeCap(SkPaint::kSquare_Cap);
	break;
      case RoundCap:
	impl_->strokePaint_.setStrokeCap(SkPaint::kRound_Cap);
	break;
      }

      switch (pen.joinStyle()) {
      case MiterJoin:
	impl_->strokePaint_.setStrokeJoin(SkPaint::kMiter_Join);
	break;
      case BevelJoin:
	impl_->strokePaint_.setStrokeJoin(SkPaint::kBevel_Join);
	break;
      case RoundJoin:
	impl_->strokePaint_.setStrokeJoin(SkPaint::kRound_Join);
	break;
      }

      SkPathEffect *pe = impl_->strokePaint_.setPathEffect(0);
      if (pe)
	pe->unref();
      switch (pen.style()) {
      case NoPen:
	break;
      case SolidLine:
	break;
      case DashLine: {
	const SkScalar dasharray[] = { SkIntToScalar(4), SkIntToScalar(2) };
	impl_->strokePaint_.setPathEffect(new SkDashPathEffect(dasharray, 2,
							false))->unref();
	break;
      }
      case DotLine: {
	const SkScalar dasharray[] = { SkIntToScalar(1), SkIntToScalar(2) };
	impl_->strokePaint_.setPathEffect(new SkDashPathEffect(dasharray, 2,
							false))->unref();
	break;
      }
      case DashDotLine: {
	const SkScalar dasharray[] = {
	  SkIntToScalar(4),
	  SkIntToScalar(2),
	  SkIntToScalar(1),
	  SkIntToScalar(2)
	};
	impl_->strokePaint_.setPathEffect(new SkDashPathEffect(dasharray, 4,
							false))->unref();
	break;
      }
      case DashDotDotLine: {
	const SkScalar dasharray[] = {
	  SkIntToScalar(4),
	  SkIntToScalar(2),
	  SkIntToScalar(1),
	  SkIntToScalar(2),
	  SkIntToScalar(1),
	  SkIntToScalar(2)
	};
	impl_->strokePaint_.setPathEffect(new SkDashPathEffect(dasharray, 6,
							false))->unref();
	break;
      }
      }

    }
  }

  if (flags & Brush) {
    const WBrush& brush = painter()->brush();
    if (brush.style() != NoBrush) {
      const WColor& color = painter()->brush().color();
      impl_->fillPaint_.setColor(fromWColor(color));
    }
  }

  if (flags & Font) {
    const WFont& font = painter()->font();

    const char *base = 0;
    switch (font.genericFamily()) {
    case WFont::Default:
    case WFont::Serif:
      base = "Times";
      break;
    case WFont::SansSerif:
      base = "Helvetica";
      break;
    case WFont::Monospace:
      base = "Courier";
      break;
    case WFont::Fantasy: // Not really !
      base = "Symbol";
      break;
    case WFont::Cursive: // Not really !
      base = "ZapfDingbats";
    }

    int style = SkTypeface::kNormal;
    if (font.style() != WFont::NormalStyle)
      style |= SkTypeface::kItalic;
    if (font.weight() == WFont::Bold ||
	font.weight() == WFont::Bolder)
      style |= SkTypeface::kBold;

    impl_->textPaint_.setTypeface(SkTypeface::CreateFromName(base,
				    (SkTypeface::Style)style))->unref();
    impl_->textPaint_.setTextSize(SkIntToScalar(font.sizeLength(12).toPixels()));
  }
}
示例#27
0
文件: blurrect.cpp 项目: molikto/Skia
 void onOnceBeforeDraw() override {
     for (int i = 0; i <= kLastEnum_SkBlurStyle; ++i) {
         fMaskFilters[i] = SkMaskFilter::MakeBlur((SkBlurStyle)i,
                               SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(STROKE_WIDTH/2)));
     }
 }
示例#28
0
void SkStroke::strokePath(const SkPath& src, SkPath* dst) const {
    SkASSERT(&src != NULL && dst != NULL);

    SkScalar radius = SkScalarHalf(fWidth);

    dst->reset();
    if (radius <= 0) {
        return;
    }
    
#ifdef SK_SCALAR_IS_FIXED
    void (*proc)(SkPoint pts[], int count) = identity_proc;
    if (needs_to_shrink(src)) {
        proc = shift_down_2_proc;
        radius >>= 2;
        if (radius == 0) {
            return;
        }
    }
#endif

    SkPathStroker   stroker(radius, fMiterLimit, this->getCap(),
                            this->getJoin());

    SkPath::Iter    iter(src, false);
    SkPoint         pts[4];
    SkPath::Verb    verb, lastSegment = SkPath::kMove_Verb;

    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
        switch (verb) {
            case SkPath::kMove_Verb:
                APPLY_PROC(proc, &pts[0], 1);
                stroker.moveTo(pts[0]);
                break;
            case SkPath::kLine_Verb:
                APPLY_PROC(proc, &pts[1], 1);
                stroker.lineTo(pts[1]);
                lastSegment = verb;
                break;
            case SkPath::kQuad_Verb:
                APPLY_PROC(proc, &pts[1], 2);
                stroker.quadTo(pts[1], pts[2]);
                lastSegment = verb;
                break;
            case SkPath::kCubic_Verb:
                APPLY_PROC(proc, &pts[1], 3);
                stroker.cubicTo(pts[1], pts[2], pts[3]);
                lastSegment = verb;
                break;
            case SkPath::kClose_Verb:
                stroker.close(lastSegment == SkPath::kLine_Verb);
                break;
            default:
                break;
        }
    }
    stroker.done(dst, lastSegment == SkPath::kLine_Verb);

#ifdef SK_SCALAR_IS_FIXED
    // undo our previous down_shift
    if (shift_down_2_proc == proc) {
        // need a real shift methid on path. antialias paths could use this too
        SkMatrix matrix;
        matrix.setScale(SkIntToScalar(4), SkIntToScalar(4));
        dst->transform(matrix);
    }
#endif

    if (fDoFill) {
        if (src.cheapIsDirection(SkPath::kCCW_Direction)) {
            dst->reverseAddPath(src);
        } else {
            dst->addPath(src);
        }
    } else {
        //  Seems like we can assume that a 2-point src would always result in
        //  a convex stroke, but testing has proved otherwise.
        //  TODO: fix the stroker to make this assumption true (without making
        //  it slower that the work that will be done in computeConvexity())
#if 0
        // this test results in a non-convex stroke :(
        static void test(SkCanvas* canvas) {
            SkPoint pts[] = { 146.333328,  192.333328, 300.333344, 293.333344 };
            SkPaint paint;
            paint.setStrokeWidth(7);
            paint.setStrokeCap(SkPaint::kRound_Cap);
            canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
        }        
#endif
#if 0
        if (2 == src.countPoints()) {
            dst->setIsConvex(true);
        }
#endif
    }
示例#29
0
////////////////////////////////////////////////////////////////////////////////
// Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device
// (as opposed to canvas) coordinates
bool GrClipMaskManager::createStencilClipMask(const GrClipData& clipDataIn,
                                              const GrIRect& devClipBounds) {

    GrAssert(kNone_ClipMaskType == fCurrClipMaskType);

    GrDrawState* drawState = fGpu->drawState();
    GrAssert(drawState->isClipState());

    GrRenderTarget* rt = drawState->getRenderTarget();
    GrAssert(NULL != rt);

    // TODO: dynamically attach a SB when needed.
    GrStencilBuffer* stencilBuffer = rt->getStencilBuffer();
    if (NULL == stencilBuffer) {
        return false;
    }

    if (stencilBuffer->mustRenderClip(clipDataIn, rt->width(), rt->height())) {

        stencilBuffer->setLastClip(clipDataIn, rt->width(), rt->height());

        // we set the current clip to the bounds so that our recursive
        // draws are scissored to them. We use the copy of the complex clip
        // we just stashed on the SB to render from. We set it back after
        // we finish drawing it into the stencil.
        const GrClipData* oldClipData = fGpu->getClip();

        // The origin of 'newClipData' is (0, 0) so it is okay to place
        // a device-coordinate bound in 'newClipStack'
        SkClipStack newClipStack(devClipBounds);
        GrClipData newClipData;
        newClipData.fClipStack = &newClipStack;

        fGpu->setClip(&newClipData);

        GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
        drawState = fGpu->drawState();
        drawState->setRenderTarget(rt);
        GrDrawTarget::AutoGeometryPush agp(fGpu);

        if (0 != clipDataIn.fOrigin.fX || 0 != clipDataIn.fOrigin.fY) {
            // Add the saveLayer's offset to the view matrix rather than
            // offset each individual draw
            drawState->viewMatrix()->setTranslate(
                           SkIntToScalar(-clipDataIn.fOrigin.fX),
                           SkIntToScalar(-clipDataIn.fOrigin.fY));
        }

#if !VISUALIZE_COMPLEX_CLIP
        drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
#endif

        int clipBit = stencilBuffer->bits();
        SkASSERT((clipBit <= 16) &&
                    "Ganesh only handles 16b or smaller stencil buffers");
        clipBit = (1 << (clipBit-1));

        GrIRect devRTRect = GrIRect::MakeWH(rt->width(), rt->height());

        bool clearToInside;
        SkRegion::Op firstOp = SkRegion::kReplace_Op; // suppress warning

        SkClipStack::Iter iter(*oldClipData->fClipStack,
                               SkClipStack::Iter::kBottom_IterStart);
        const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter,
                                                  devRTRect,
                                                  &clearToInside,
                                                  &firstOp,
                                                  clipDataIn);

        fGpu->clearStencilClip(devClipBounds, clearToInside);
        bool first = true;

        // walk through each clip element and perform its set op
        // with the existing clip.
        for ( ; NULL != clip; clip = iter.next()) {
            GrPathFill fill;
            bool fillInverted = false;
            // enabled at bottom of loop
            drawState->disableState(GrGpu::kModifyStencilClip_StateBit);
            // if the target is MSAA then we want MSAA enabled when the clip is soft
            if (rt->isMultisampled()) {
                if (clip->fDoAA) {
                    drawState->enableState(GrDrawState::kHWAntialias_StateBit);
                } else {
                    drawState->disableState(GrDrawState::kHWAntialias_StateBit);
                }
            }

            // Can the clip element be drawn directly to the stencil buffer
            // with a non-inverted fill rule without extra passes to
            // resolve in/out status?
            bool canRenderDirectToStencil = false;

            SkRegion::Op op = clip->fOp;
            if (first) {
                first = false;
                op = firstOp;
            }

            GrPathRenderer* pr = NULL;
            const SkPath* clipPath = NULL;
            if (NULL != clip->fRect) {
                canRenderDirectToStencil = true;
                fill = kEvenOdd_GrPathFill;
                fillInverted = false;
                // there is no point in intersecting a screen filling
                // rectangle.
                if (SkRegion::kIntersect_Op == op &&
                    contains(*clip->fRect, devRTRect, oldClipData->fOrigin)) {
                    continue;
                }
            } else {
                GrAssert(NULL != clip->fPath);
                fill = get_path_fill(*clip->fPath);
                fillInverted = GrIsFillInverted(fill);
                fill = GrNonInvertedFill(fill);
                clipPath = clip->fPath;
                pr = this->getContext()->getPathRenderer(*clipPath, fill, fGpu, false, true);
                if (NULL == pr) {
                    fGpu->setClip(oldClipData);
                    return false;
                }
                canRenderDirectToStencil =
                    !pr->requiresStencilPass(*clipPath, fill, fGpu);
            }

            int passes;
            GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];

            bool canDrawDirectToClip; // Given the renderer, the element,
                                        // fill rule, and set operation can
                                        // we render the element directly to
                                        // stencil bit used for clipping.
            canDrawDirectToClip =
                GrStencilSettings::GetClipPasses(op,
                                                 canRenderDirectToStencil,
                                                 clipBit,
                                                 fillInverted,
                                                 &passes,
                                                 stencilSettings);

            // draw the element to the client stencil bits if necessary
            if (!canDrawDirectToClip) {
                GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil,
                    kIncClamp_StencilOp,
                    kIncClamp_StencilOp,
                    kAlways_StencilFunc,
                    0xffff,
                    0x0000,
                    0xffff);
                SET_RANDOM_COLOR
                if (NULL != clip->fRect) {
                    *drawState->stencil() = gDrawToStencil;
                    fGpu->drawSimpleRect(*clip->fRect, NULL);
                } else {
                    if (canRenderDirectToStencil) {
                        *drawState->stencil() = gDrawToStencil;
                        pr->drawPath(*clipPath, fill, NULL, fGpu, false);
                    } else {
                        pr->drawPathToStencil(*clipPath, fill, fGpu);
                    }
                }
            }

            // now we modify the clip bit by rendering either the clip
            // element directly or a bounding rect of the entire clip.
            drawState->enableState(GrGpu::kModifyStencilClip_StateBit);
            for (int p = 0; p < passes; ++p) {
                *drawState->stencil() = stencilSettings[p];
                if (canDrawDirectToClip) {
                    if (NULL != clip->fRect) {
                        SET_RANDOM_COLOR
                        fGpu->drawSimpleRect(*clip->fRect, NULL);
                    } else {
                        SET_RANDOM_COLOR
                        pr->drawPath(*clipPath, fill, NULL, fGpu, false);
                    }
                } else {
                    SET_RANDOM_COLOR
                    // 'devClipBounds' is already in device coordinates so the
                    // translation in the view matrix is inappropriate.
                    // Convert it to canvas space so the drawn rect will
                    // be in the correct location
                    GrRect canvClipBounds;
                    canvClipBounds.set(devClipBounds);
                    device_to_canvas(&canvClipBounds, clipDataIn.fOrigin);
                    fGpu->drawSimpleRect(canvClipBounds, NULL);
                }
            }
        }
示例#30
0
    virtual void onDraw(SkCanvas* canvas) {
        this->init();

        SkPaint paint;
        SkColorMatrix matrix;

        paint.setXfermodeMode(SkXfermode::kSrc_Mode);
        const SkBitmap bmps[] = { fSolidBitmap, fTransparentBitmap };

        for (size_t i = 0; i < SK_ARRAY_COUNT(bmps); ++i) {

            matrix.setIdentity();
            setColorMatrix(&paint, matrix);
            canvas->drawBitmap(bmps[i], 0, 0, &paint);

            matrix.setRotate(SkColorMatrix::kR_Axis, 90);
            setColorMatrix(&paint, matrix);
            canvas->drawBitmap(bmps[i], 80, 0, &paint);

            matrix.setRotate(SkColorMatrix::kG_Axis, 90);
            setColorMatrix(&paint, matrix);
            canvas->drawBitmap(bmps[i], 160, 0, &paint);

            matrix.setRotate(SkColorMatrix::kB_Axis, 90);
            setColorMatrix(&paint, matrix);
            canvas->drawBitmap(bmps[i], 240, 0, &paint);

            matrix.setSaturation(0.0f);
            setColorMatrix(&paint, matrix);
            canvas->drawBitmap(bmps[i], 0, 80, &paint);

            matrix.setSaturation(0.5f);
            setColorMatrix(&paint, matrix);
            canvas->drawBitmap(bmps[i], 80, 80, &paint);

            matrix.setSaturation(1.0f);
            setColorMatrix(&paint, matrix);
            canvas->drawBitmap(bmps[i], 160, 80, &paint);

            matrix.setSaturation(2.0f);
            setColorMatrix(&paint, matrix);
            canvas->drawBitmap(bmps[i], 240, 80, &paint);

            matrix.setRGB2YUV();
            setColorMatrix(&paint, matrix);
            canvas->drawBitmap(bmps[i], 0, 160, &paint);

            matrix.setYUV2RGB();
            setColorMatrix(&paint, matrix);
            canvas->drawBitmap(bmps[i], 80, 160, &paint);

            SkScalar s1 = SK_Scalar1;
            SkScalar s255 = SkIntToScalar(255);
            // Move red into alpha, set color to white
            SkScalar data[20] = {
                0,  0, 0, 0, s255,
                0,  0, 0, 0, s255,
                0,  0, 0, 0, s255,
                s1, 0, 0, 0, 0,
            };

            setArray(&paint, data);
            canvas->drawBitmap(bmps[i], 160, 160, &paint);

            canvas->translate(0, 240);
        }
    }