LooperView() {
        static const struct {
            SkColor         fColor;
            SkPaint::Style  fStyle;
            SkScalar        fWidth;
            SkScalar        fOffset;
            int             fBlur;
        } gParams[] = {
            { SK_ColorWHITE, SkPaint::kStroke_Style, SkIntToScalar(1)*3/4, 0, 0 },
            { SK_ColorRED, SkPaint::kStroke_Style, SkIntToScalar(4), 0, 0 },
            { SK_ColorBLUE, SkPaint::kFill_Style, 0, 0, 0 },
            { 0x88000000, SkPaint::kFill_Style, 0, SkIntToScalar(10), 3 }
        };

        fLooper = new SkLayerDrawLooper;

        for (int i = 0; i < SK_ARRAY_COUNT(gParams); i++) {
            SkPaint* paint = fLooper->addLayer(gParams[i].fOffset,
                                               gParams[i].fOffset);
            paint->setAntiAlias(true);
            paint->setColor(gParams[i].fColor);
            paint->setStyle(gParams[i].fStyle);
            paint->setStrokeWidth(gParams[i].fWidth);
            paint->setTextSize(SkIntToScalar(72));
            if (gParams[i].fBlur > 0) {
                SkMaskFilter* mf = SkBlurMaskFilter::Create(SkIntToScalar(gParams[i].fBlur),
                                                            SkBlurMaskFilter::kNormal_BlurStyle);
                paint->setMaskFilter(mf)->unref();
            }
        }
    }
static bool setupForText(SkPaint* paint, GraphicsContext* gc,
                         const SimpleFontData* font) {
    int mode = gc->textDrawingMode();
    
    if ((mode & (cTextFill | cTextStroke)) == (cTextFill | cTextStroke)) {
        SkLayerDrawLooper* looper = new SkLayerDrawLooper;
        paint->setLooper(looper)->unref();
        
        // we clear the looper, in case we have a shadow

        SkPaint* fillP = NULL;
        SkPaint* strokeP = NULL;
        if (gc->willStroke()) {
            strokeP = setupStroke(looper->addLayer(), gc, font);
            strokeP->setLooper(NULL);
        }
        if (gc->willFill()) {
            fillP = setupFill(looper->addLayer(), gc, font);
            fillP->setLooper(NULL);
        }

        SkPaint shadowPaint;
        SkPoint offset;
        if (gc->setupShadowPaint(&shadowPaint, &offset)) {
            SkPaint* p = looper->addLayer(offset.fX, offset.fY);
            *p = shadowPaint;
            if (strokeP && !fillP) {
                // stroke the shadow if we have stroke but no fill
                p->setStyle(SkPaint::kStroke_Style);
                p->setStrokeWidth(strokeP->getStrokeWidth());
            }
            updateForFont(p, font);
        }
    } else if (mode & cTextFill) {
        (void)setupFill(paint, gc, font);
    } else if (mode & cTextStroke) {
        (void)setupStroke(paint, gc, font);
    } else {
        return false;
    }
    return true;
}
void
DrawTargetSkia::DrawSurfaceWithShadow(SourceSurface *aSurface,
                                      const Point &aDest,
                                      const Color &aColor,
                                      const Point &aOffset,
                                      Float aSigma,
                                      CompositionOp aOperator)
{
    MarkChanged();
    mCanvas->save(SkCanvas::kMatrix_SaveFlag);
    mCanvas->resetMatrix();

    uint32_t blurFlags = SkBlurMaskFilter::kHighQuality_BlurFlag |
                         SkBlurMaskFilter::kIgnoreTransform_BlurFlag;
    const SkBitmap& bitmap = static_cast<SourceSurfaceSkia*>(aSurface)->GetBitmap();
    SkShader* shader = SkShader::CreateBitmapShader(bitmap, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
    SkMatrix matrix;
    matrix.reset();
    matrix.setTranslateX(SkFloatToScalar(aDest.x));
    matrix.setTranslateY(SkFloatToScalar(aDest.y));
    shader->setLocalMatrix(matrix);
    SkLayerDrawLooper* dl = new SkLayerDrawLooper;
    SkLayerDrawLooper::LayerInfo info;
    info.fPaintBits |= SkLayerDrawLooper::kShader_Bit;
    SkPaint *layerPaint = dl->addLayer(info);
    layerPaint->setShader(shader);

    info.fPaintBits = 0;
    info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit;
    info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit;
    info.fColorMode = SkXfermode::kDst_Mode;
    info.fOffset.set(SkFloatToScalar(aOffset.x), SkFloatToScalar(aOffset.y));
    info.fPostTranslate = true;

    SkMaskFilter* mf = SkBlurMaskFilter::Create(aSigma, SkBlurMaskFilter::kNormal_BlurStyle, blurFlags);
    SkColor color = ColorToSkColor(aColor, 1);
    SkColorFilter* cf = SkColorFilter::CreateModeFilter(color, SkXfermode::kSrcIn_Mode);


    layerPaint = dl->addLayer(info);
    SkSafeUnref(layerPaint->setMaskFilter(mf));
    SkSafeUnref(layerPaint->setColorFilter(cf));
    layerPaint->setColor(color);

    // TODO: This is using the rasterizer to calculate an alpha mask
    // on both the shadow and normal layers. We should fix this
    // properly so it only happens for the shadow layer
    SkLayerRasterizer *raster = new SkLayerRasterizer();
    SkPaint maskPaint;
    SkSafeUnref(maskPaint.setShader(shader));
    raster->addLayer(maskPaint, 0, 0);

    SkPaint paint;
    paint.setAntiAlias(true);
    SkSafeUnref(paint.setRasterizer(raster));
    paint.setXfermodeMode(GfxOpToSkiaOp(aOperator));
    SkSafeUnref(paint.setLooper(dl));

    SkRect rect = RectToSkRect(Rect(Float(aDest.x), Float(aDest.y),
                                    Float(bitmap.width()), Float(bitmap.height())));
    mCanvas->drawRect(rect, paint);
    mCanvas->restore();
}
Exemple #4
0
static bool setupForText(SkPaint* paint, GraphicsContext* gc,
                         const SimpleFontData* font) {
    int mode = gc->textDrawingMode() & (TextModeFill | TextModeStroke);
    if (!mode)
        return false;

    paint->setVerticalText(font->platformData().orientation() == Vertical);

    FloatSize shadowOffset;
    float shadowBlur;
    Color shadowColor;
    ColorSpace shadowColorSpace;

    if (RenderSkinAndroid::DrawableResolution() >= RenderSkinAndroid::HighRes)
        paint->setAutohinted(false);

    bool hasShadow = gc->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);
    bool hasBothStrokeAndFill =
        (mode & (TextModeStroke | TextModeFill)) == (TextModeStroke | TextModeFill);
    if (hasShadow || hasBothStrokeAndFill) {
        SkLayerDrawLooper* looper = new SkLayerDrawLooper;
        paint->setLooper(looper)->unref();

        // The layerDrawLooper uses at the root paint to determine the text
        // encoding so we need to make sure it is properly configured.
        updateForFont(paint, font);

        // Specify the behavior of the looper
        SkLayerDrawLooper::LayerInfo info;
        info.fPaintBits = SkLayerDrawLooper::kEntirePaint_Bits;
        info.fColorMode = SkXfermode::kSrc_Mode;
        info.fFlagsMask = SkPaint::kAllFlags;

        // The paint is only valid until the looper receives another call to
        // addLayer(). Therefore, we must cache certain state for later use.
        bool hasFillPaint = false;
        bool hasStrokePaint = false;
        SkScalar strokeWidth;

        if ((mode & TextModeStroke) && gc->willStroke()) {
            strokeWidth = setupStroke(looper->addLayer(info), gc, font)->getStrokeWidth();
            hasStrokePaint = true;
        }
        if ((mode & TextModeFill) && gc->willFill()) {
            setupFill(looper->addLayer(info), gc, font);
            hasFillPaint = true;
        }

        if (hasShadow) {
            SkPaint shadowPaint;
            SkPoint offset;
            if (gc->setupShadowPaint(&shadowPaint, &offset)) {

                // add an offset to the looper when creating a shadow layer
                info.fOffset.set(offset.fX, offset.fY);

                SkPaint* p = looper->addLayer(info);
                *p = shadowPaint;

                // Currently, only GraphicsContexts associated with the
                // HTMLCanvasElement have shadows ignore transforms set.  This
                // allows us to distinguish between CSS and Canvas shadows which
                // have different rendering specifications.
                if (gc->shadowsIgnoreTransforms()) {
                    SkColorFilter* cf = SkColorFilter::CreateModeFilter(p->getColor(),
                            SkXfermode::kSrcIn_Mode);
                    p->setColorFilter(cf)->unref();
                } else { // in CSS
                    p->setShader(NULL);
                }

                if (hasStrokePaint && !hasFillPaint) {
                    // stroke the shadow if we have stroke but no fill
                    p->setStyle(SkPaint::kStroke_Style);
                    p->setStrokeWidth(strokeWidth);
                }
                updateForFont(p, font);
            }
        }
    } else if (mode & TextModeFill) {
        (void)setupFill(paint, gc, font);
    } else if (mode & TextModeStroke) {
        (void)setupStroke(paint, gc, font);
    } else {
        return false;
    }
    return true;
}
void GraphicsContext::setPlatformShadow(const FloatSize& size,
                                        float blurFloat,
                                        const Color& color,
                                        ColorSpace colorSpace)
{
    if (paintingDisabled())
        return;

    // Detect when there's no effective shadow and clear the looper.
    if (!size.width() && !size.height() && !blurFloat) {
        platformContext()->setDrawLooper(0);
        return;
    }

    double width = size.width();
    double height = size.height();
    double blur = blurFloat;

    uint32_t mfFlags = SkBlurMaskFilter::kHighQuality_BlurFlag;
    SkXfermode::Mode colorMode = SkXfermode::kSrc_Mode;

    if (m_state.shadowsIgnoreTransforms)  {
        // Currently only the GraphicsContext associated with the
        // CanvasRenderingContext for HTMLCanvasElement have shadows ignore
        // Transforms. So with this flag set, we know this state is associated
        // with a CanvasRenderingContext.
        mfFlags |= SkBlurMaskFilter::kIgnoreTransform_BlurFlag;

        // CSS wants us to ignore the original's alpha, but Canvas wants us to
        // modulate with it. Using shadowsIgnoreTransforms to tell us that we're
        // in a Canvas, we change the colormode to kDst_Mode, so we don't overwrite
        // it with our layer's (default opaque-black) color.
        colorMode = SkXfermode::kDst_Mode;

        // CG uses natural orientation for Y axis, but the HTML5 canvas spec
        // does not.
        // So we now flip the height since it was flipped in
        // CanvasRenderingContext in order to work with CG.
        height = -height;
    }

    SkColor c;
    if (color.isValid())
        c = color.rgb();
    else
        c = SkColorSetARGB(0xFF/3, 0, 0, 0);    // "std" apple shadow color.

    // TODO(tc): Should we have a max value for the blur?  CG clamps at 1000.0
    // for perf reasons.

    SkLayerDrawLooper* dl = new SkLayerDrawLooper;
    SkAutoUnref aur(dl);

    // top layer, we just draw unchanged
    dl->addLayer();

    // lower layer contains our offset, blur, and colorfilter
    SkLayerDrawLooper::LayerInfo info;

    info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit; // our blur
    info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit;
    info.fColorMode = colorMode;
    info.fOffset.set(width, height);
    info.fPostTranslate = m_state.shadowsIgnoreTransforms;

    SkMaskFilter* mf = SkBlurMaskFilter::Create(blur / 2, SkBlurMaskFilter::kNormal_BlurStyle, mfFlags);

    SkColorFilter* cf = SkColorFilter::CreateModeFilter(c, SkXfermode::kSrcIn_Mode);

    SkPaint* paint = dl->addLayer(info);
    SkSafeUnref(paint->setMaskFilter(mf));
    SkSafeUnref(paint->setColorFilter(cf));

    // dl is now built, just install it
    platformContext()->setDrawLooper(dl);
}