From a12f388a8c7cc2c9acce41303d6df6ebef410482 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Sun, 16 Nov 2014 17:44:16 -0800 Subject: [PATCH] Implement a `DrawShadow` method for `box-shadow`. This is closely modeled on the way Chromium does it. --- libazure/include/mozilla/gfx/2D.h | 18 ++++++++++ libazure/src/gfx/2d/DrawTargetSkia.cpp | 46 ++++++++++++++++++++++++++ libazure/src/gfx/2d/DrawTargetSkia.h | 5 +++ src/azure-c.cpp | 19 +++++++++++ src/azure-c.h | 10 ++++-- src/azure.rs | 7 ++++ src/azure_hl.rs | 21 ++++++++++-- 7 files changed, 121 insertions(+), 5 deletions(-) diff --git a/libazure/include/mozilla/gfx/2D.h b/libazure/include/mozilla/gfx/2D.h index d936dba..47cdaaa 100644 --- a/libazure/include/mozilla/gfx/2D.h +++ b/libazure/include/mozilla/gfx/2D.h @@ -708,6 +708,24 @@ class DrawTarget : public RefCounted const Pattern &aMask, const DrawOptions &aOptions = DrawOptions()) = 0; + /* + * Draws a shadow around the given path. The transform *is* taken into + * account, unlike |DrawSurfaceWithShadow()|. + * + * aPath Path that is to be shadowed + * aColor The color of the shadow + * aOffset The offset of the shadow from the path + * aSigma The sigma for the blur + * aOperator The composition operator for the operation + */ + virtual void DrawShadow(const Path &aPath, + const Color &aColor, + const Point &aOffset, + Float aSigma, + CompositionOp aOperator) { + // Default: no-op. + } + /* * Push a clip to the DrawTarget. * diff --git a/libazure/src/gfx/2d/DrawTargetSkia.cpp b/libazure/src/gfx/2d/DrawTargetSkia.cpp index 1a81a33..ff745db 100644 --- a/libazure/src/gfx/2d/DrawTargetSkia.cpp +++ b/libazure/src/gfx/2d/DrawTargetSkia.cpp @@ -423,6 +423,52 @@ DrawTargetSkia::StrokeLine(const Point &aStart, paint.mPaint); } +void +DrawTargetSkia::DrawShadow(const Path &aPath, + const Color &aColor, + const Point &aOffset, + Float aSigma, + CompositionOp aOperator) +{ + MarkChanged(); + + if (aPath.GetBackendType() != BACKEND_SKIA) { + return; + } + const PathSkia *skiaPath = static_cast(&aPath); + + uint32_t blurFlags = SkBlurMaskFilter::kHighQuality_BlurFlag; + SkLayerDrawLooper* dl = new SkLayerDrawLooper; + SkLayerDrawLooper::LayerInfo info; + + info.fPaintBits = 0; + info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit; + info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit; + info.fColorMode = SkXfermode::kSrc_Mode; + info.fOffset.set(SkFloatToScalar(aOffset.x), SkFloatToScalar(aOffset.y)); + info.fPostTranslate = false; + + SkMaskFilter* mf = SkBlurMaskFilter::Create(aSigma, + SkBlurMaskFilter::kNormal_BlurStyle, + blurFlags); + SkColor color = ColorToSkColor(aColor, 1); + SkColorFilter* cf = SkColorFilter::CreateModeFilter(color, SkXfermode::kSrcIn_Mode); + + SkPaint *layerPaint = dl->addLayer(info); + SkSafeUnref(layerPaint->setMaskFilter(mf)); + SkSafeUnref(layerPaint->setColorFilter(cf)); + layerPaint->setColor(color); + + SkPaint paint; + paint.setColor(SkColorSetARGB(255, 0, 0, 0)); + paint.setAntiAlias(true); + paint.setXfermodeMode(GfxOpToSkiaOp(aOperator)); + SkSafeUnref(paint.setLooper(dl)); + + mCanvas->drawPath(skiaPath->GetPath(), paint); + mCanvas->restore(); +} + void DrawTargetSkia::Fill(const Path *aPath, const Pattern &aPattern, diff --git a/libazure/src/gfx/2d/DrawTargetSkia.h b/libazure/src/gfx/2d/DrawTargetSkia.h index 02f315b..d15618e 100644 --- a/libazure/src/gfx/2d/DrawTargetSkia.h +++ b/libazure/src/gfx/2d/DrawTargetSkia.h @@ -75,6 +75,11 @@ class DrawTargetSkia : public DrawTarget virtual void Mask(const Pattern &aSource, const Pattern &aMask, const DrawOptions &aOptions = DrawOptions()); + virtual void DrawShadow(const Path &aPath, + const Color &aColor, + const Point &aOffset, + Float aSigma, + CompositionOp aOperator); virtual void PushClip(const Path *aPath); virtual void PushClipRect(const Rect& aRect); virtual void PopClip(); diff --git a/src/azure-c.cpp b/src/azure-c.cpp index ab5d5d9..db63dd2 100644 --- a/src/azure-c.cpp +++ b/src/azure-c.cpp @@ -320,6 +320,25 @@ AzDrawTargetFillRect(AzDrawTargetRef aDrawTarget, gfxDrawOptions != NULL ? *gfxDrawOptions : gfx::DrawOptions()); } +extern "C" void +AzDrawTargetDrawShadow(AzDrawTargetRef aDrawTarget, + AzPathRef aPath, + const AzColor *aColor, + const AzPoint *aOffset, + AzFloat aSigma, + AzCompositionOp aOperator) { + gfx::DrawTarget *gfxDrawTarget = static_cast(aDrawTarget); + gfx::Path *gfxPath = reinterpret_cast(aPath); + const gfx::Color *gfxColor = reinterpret_cast(aColor); + const gfx::Point *gfxOffset = reinterpret_cast(aOffset); + gfx::CompositionOp gfxOperator = static_cast(aOperator); + gfxDrawTarget->DrawShadow(*gfxPath, + *gfxColor, + *gfxOffset, + aSigma, + gfxOperator); +} + extern "C" void AzDrawTargetStrokeRect(AzDrawTargetRef aDrawTarget, AzRect *aRect, AzPatternRef aPattern, AzStrokeOptions *aStrokeOptions, diff --git a/src/azure-c.h b/src/azure-c.h index 65c2d67..9548349 100644 --- a/src/azure-c.h +++ b/src/azure-c.h @@ -333,9 +333,15 @@ AzIntSize AzDrawTargetGetSize(AzDrawTargetRef aDrawTarget); void AzDrawTargetFlush(AzDrawTargetRef aDrawTarget); void AzDrawTargetClearRect(AzDrawTargetRef aDrawTarget, AzRect *aRect); void AzDrawTargetFillRect(AzDrawTargetRef aDrawTarget, - AzRect* aRect, - AzPatternRef aPattern, + AzRect* aRect, + AzPatternRef aPattern, AzDrawOptions* aDrawOptions); +void AzDrawTargetDrawShadow(AzDrawTargetRef aDrawTarget, + AzPathRef aPath, + const AzColor *aColor, + const AzPoint *aOffset, + AzFloat aSigma, + AzCompositionOp aOperator); void AzDrawTargetStrokeRect(AzDrawTargetRef aDrawTarget, AzRect *aRect, AzPatternRef aPattern, diff --git a/src/azure.rs b/src/azure.rs index db360bd..dd0fb6e 100644 --- a/src/azure.rs +++ b/src/azure.rs @@ -376,6 +376,13 @@ pub fn AzDrawTargetFillRect(aDrawTarget: AzDrawTargetRef, aPattern: AzPatternRef, aDrawOptions: *mut AzDrawOptions); +pub fn AzDrawTargetDrawShadow(aDrawTarget: AzDrawTargetRef, + aPath: AzPathRef, + aColor: *const AzColor, + aPoint: *const AzPoint, + aSigma: AzFloat, + aOperator: AzCompositionOp); + pub fn AzDrawTargetStrokeRect(aDrawTarget: AzDrawTargetRef, aRect: *mut AzRect, aPattern: AzPatternRef, aStrokeOptions: *mut AzStrokeOptions, aDrawOptions: *mut AzDrawOptions); pub fn AzDrawTargetStrokeLine(aDrawTarget: AzDrawTargetRef, aStart: *mut AzPoint, aEnd: *mut AzPoint, aPattern: AzPatternRef, aStrokeOptions: *mut AzStrokeOptions, aDrawOptions: *mut AzDrawOptions); diff --git a/src/azure_hl.rs b/src/azure_hl.rs index 3ae2069..4e68eda 100644 --- a/src/azure_hl.rs +++ b/src/azure_hl.rs @@ -22,7 +22,7 @@ use azure::{AzReleaseSkiaSharedGLContext, AzRetainSkiaSharedGLContext}; use azure::{AzDrawTargetDrawSurface, AzDrawTargetFillRect, AzDrawTargetFlush}; use azure::{AzDrawTargetGetSize, AzDrawTargetGetSnapshot, AzDrawTargetSetTransform}; use azure::{AzDrawTargetStrokeLine, AzDrawTargetStrokeRect, AzDrawTargetFillGlyphs}; -use azure::{AzDrawTargetCreateGradientStops}; +use azure::{AzDrawTargetCreateGradientStops, AzDrawTargetDrawShadow}; use azure::{AzReleaseDrawTarget, AzReleasePattern, AzReleaseGradientStops}; use azure::{AzReleaseSourceSurface, AzRetainDrawTarget}; use azure::{AzSourceSurfaceGetDataSurface, AzSourceSurfaceGetFormat}; @@ -92,7 +92,7 @@ impl AsAzurePoint for Point2D { } } -#[deriving(Clone)] +#[deriving(Clone, Show)] pub struct Color { pub r: AzFloat, pub g: AzFloat, @@ -111,7 +111,6 @@ impl Color { } -// FIXME: Should have a class hierarchy here starting with Pattern. pub struct ColorPattern { pub azure_color_pattern: AzColorPatternRef, } @@ -503,6 +502,22 @@ impl DrawTarget { } } + pub fn draw_shadow(&self, + path: &Path, + color: &Color, + point: &Point2D, + sigma: AzFloat, + operator: CompositionOp) { + unsafe { + AzDrawTargetDrawShadow(self.azure_draw_target, + path.azure_path, + &color.as_azure_color(), + &point.as_azure_point(), + sigma, + operator as AzCompositionOp) + } + } + pub fn stroke_line(&self, start: Point2D, end: Point2D,