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(); }
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); }