Skip to content

Commit

Permalink
fix: image shadow
Browse files Browse the repository at this point in the history
  • Loading branch information
doodlewind committed Feb 22, 2021
1 parent 336549d commit 8396b93
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 36 deletions.
42 changes: 40 additions & 2 deletions skia-c/skia_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <include/core/SkPaint.h>
#include <include/core/SkSurface.h>
#include <include/effects/SkDashPathEffect.h>
#include <include/effects/SkDropShadowImageFilter.h>
#include <include/effects/SkImageFilters.h>
#include <include/effects/SkGradientShader.h>
#include <include/pathops/SkPathOps.h>
#include <include/utils/SkParsePath.h>
Expand All @@ -22,6 +24,7 @@
#define PATH_CAST reinterpret_cast<SkPath *>(c_path)
#define MATRIX_CAST reinterpret_cast<SkMatrix *>(c_matrix)
#define MASK_FILTER_CAST reinterpret_cast<SkMaskFilter *>(c_mask_filter)
#define IMAGE_FILTER_CAST reinterpret_cast<SkImageFilter *>(c_image_filter)

extern "C"
{
Expand Down Expand Up @@ -222,11 +225,12 @@ extern "C"
CANVAS_CAST->drawColor(SkColor4f{r, g, b, a});
}

void skiac_canvas_draw_image(skiac_canvas *c_canvas, skiac_bitmap *c_bitmap, float sx, float sy, float s_width, float s_height, float dx, float dy, float d_width, float d_height)
void skiac_canvas_draw_image(skiac_canvas *c_canvas, skiac_bitmap *c_bitmap, float sx, float sy, float s_width, float s_height, float dx, float dy, float d_width, float d_height, skiac_paint *c_paint)
{
auto src_rect = SkRect::MakeXYWH(sx, sy, s_width, s_height);
auto dst_rect = SkRect::MakeXYWH(dx, dy, d_width, d_height);
CANVAS_CAST->drawBitmapRect(*BITMAP_CAST, src_rect, dst_rect, nullptr);
// SkDebugf("%f\n", PAINT_CAST->getStyle());
CANVAS_CAST->drawBitmapRect(*BITMAP_CAST, src_rect, dst_rect, PAINT_CAST);
}

void skiac_canvas_draw_path(skiac_canvas *c_canvas, skiac_path *c_path, skiac_paint *c_paint)
Expand Down Expand Up @@ -397,6 +401,14 @@ extern "C"
PAINT_CAST->setMaskFilter(maskFilter);
}

void skiac_paint_set_image_filter(skiac_paint *c_paint, skiac_image_filter *c_image_filter)
{
sk_sp<SkImageFilter> imageFilter(reinterpret_cast<SkImageFilter *>(c_image_filter));
imageFilter->ref();

PAINT_CAST->setImageFilter(imageFilter);
}

void skiac_paint_set_style(skiac_paint *c_paint, int style)
{
PAINT_CAST->setStyle((SkPaint::Style)style);
Expand Down Expand Up @@ -746,9 +758,14 @@ extern "C"
delete MATRIX_CAST;
}

// SkMaskFilter

skiac_mask_filter *skiac_mask_filter_make_blur(float radius)
{
auto mask_filter = SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle, radius, false).release();

auto mode = SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode;
auto image_filter = SkDropShadowImageFilter::Make(0, 0, 0, 0, 0, mode, nullptr);
if (mask_filter)
{
return reinterpret_cast<skiac_mask_filter *>(mask_filter);
Expand All @@ -765,6 +782,27 @@ extern "C"
SkSafeUnref(mask_filter);
}

// SkImageFilter

skiac_image_filter *skiac_image_filter_make_drop_shadow(float dx, float dy, float sigma_x, float sigma_y, uint32_t color)
{
auto filter = SkImageFilters::DropShadowOnly(dx, dy, sigma_x, sigma_y, color, nullptr).release();
if (filter)
{
return reinterpret_cast<skiac_image_filter *>(filter);
}
else
{
return nullptr;
}
}

void skiac_image_filter_destroy(skiac_image_filter *c_image_filter)
{
auto image_filter = IMAGE_FILTER_CAST;
SkSafeUnref(image_filter);
}

// SkData

void skiac_sk_data_destroy(skiac_data *c_data)
Expand Down
20 changes: 7 additions & 13 deletions skia-c/skia_c.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ typedef struct skiac_shader skiac_shader;
typedef struct skiac_path_effect skiac_path_effect;
typedef struct skiac_matrix skiac_matrix;
typedef struct skiac_mask_filter skiac_mask_filter;
typedef struct skiac_image_filter skiac_image_filter;
typedef struct skiac_data skiac_data;
typedef struct skiac_image skiac_image;
typedef struct skiac_bitmap skiac_bitmap;
Expand Down Expand Up @@ -88,7 +89,7 @@ extern "C"
skiac_transform skiac_canvas_get_total_transform(skiac_canvas *c_canvas);
skiac_matrix *skiac_canvas_get_total_transform_matrix(skiac_canvas *c_canvas);
void skiac_canvas_draw_color(skiac_canvas *c_canvas, float r, float g, float b, float a);
void skiac_canvas_draw_image(skiac_canvas *c_canvas, skiac_bitmap *c_bitmap, float sx, float sy, float s_width, float s_height, float dx, float dy, float d_width, float d_height);
void skiac_canvas_draw_image(skiac_canvas *c_canvas, skiac_bitmap *c_bitmap, float sx, float sy, float s_width, float s_height, float dx, float dy, float d_width, float d_height, skiac_paint *c_paint);
void skiac_canvas_draw_path(skiac_canvas *c_canvas, skiac_path *c_path, skiac_paint *c_paint);
void skiac_canvas_draw_rect(
skiac_canvas *c_canvas,
Expand Down Expand Up @@ -137,6 +138,7 @@ extern "C"
float skiac_paint_get_stroke_miter(skiac_paint *c_paint);
void skiac_paint_set_path_effect(skiac_paint *c_paint, skiac_path_effect *c_path_effect);
void skiac_paint_set_mask_filter(skiac_paint *c_paint, skiac_mask_filter *c_mask_filter);
void skiac_paint_set_image_filter(skiac_paint *c_paint, skiac_image_filter *c_image_filter);

// Path
skiac_path *skiac_path_create();
Expand Down Expand Up @@ -176,7 +178,6 @@ extern "C"
int tile_mode,
uint32_t flags,
skiac_transform c_ts);

skiac_shader *skiac_shader_make_two_point_conical_gradient(
skiac_point start_point,
float start_radius,
Expand All @@ -188,37 +189,30 @@ extern "C"
int tile_mode,
uint32_t flags,
skiac_transform c_ts);

skiac_shader *skiac_shader_make_from_surface_image(
skiac_surface *c_surface,
skiac_transform c_ts,
int filter_quality);

void skiac_shader_destroy(skiac_shader *c_shader);

// Matrix
skiac_matrix *skiac_matrix_create();

skiac_matrix *skiac_matrix_clone(skiac_matrix *c_matrix);

void skiac_matrix_pre_translate(skiac_matrix *c_matrix, float dx, float dy);

void skiac_matrix_pre_rotate(skiac_matrix *c_matrix, float degrees);

bool skiac_matrix_invert(skiac_matrix *c_matrix, skiac_matrix *inverse);

skiac_transform skiac_matrix_to_transform(skiac_matrix *c_matrix);

void skiac_matrix_destroy(skiac_matrix *c_matrix);

// MaskFilter

skiac_mask_filter *skiac_mask_filter_make_blur(float radius);

void skiac_mask_filter_destroy(skiac_mask_filter *c_mask_filter);

// SkData
// ImageFilter
skiac_image_filter *skiac_image_filter_make_drop_shadow(float dx, float dy, float sigma_x, float sigma_y, uint32_t color);
void skiac_image_filter_destroy(skiac_image_filter *c_image_filter);

// SkData
void skiac_sk_data_destroy(skiac_data *c_data);

// Bitmap
Expand Down
110 changes: 90 additions & 20 deletions src/ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ impl Context {
#[inline(always)]
pub fn stroke_rect(&mut self, x: f32, y: f32, w: f32, h: f32) -> result::Result<(), SkError> {
let stroke_paint = self.stroke_paint()?;
if let Some(shadow_paint) = self.shadow_paint(&stroke_paint) {
if let Some(shadow_paint) = self.shadow_blur_paint(&stroke_paint) {
let surface = &mut self.surface;
let last_state = self.states.last().unwrap();
surface.save();
Expand All @@ -194,7 +194,7 @@ impl Context {
#[inline(always)]
pub fn fill_rect(&mut self, x: f32, y: f32, w: f32, h: f32) -> result::Result<(), SkError> {
let fill_paint = self.fill_paint()?;
if let Some(shadow_paint) = self.shadow_paint(&fill_paint) {
if let Some(shadow_paint) = self.shadow_blur_paint(&fill_paint) {
let surface = &mut self.surface;
let last_state = self.states.last().unwrap();
surface.save();
Expand All @@ -216,7 +216,7 @@ impl Context {
pub fn stroke(&mut self, path: Option<&Path>) -> Result<()> {
let p = path.unwrap_or(&self.path);
let stroke_paint = self.stroke_paint()?;
if let Some(shadow_paint) = self.shadow_paint(&stroke_paint) {
if let Some(shadow_paint) = self.shadow_blur_paint(&stroke_paint) {
let surface = &mut self.surface;
let last_state = self.states.last().unwrap();
surface.save();
Expand Down Expand Up @@ -247,7 +247,7 @@ impl Context {
&self.path
};
let fill_paint = self.fill_paint()?;
if let Some(shadow_paint) = self.shadow_paint(&fill_paint) {
if let Some(shadow_paint) = self.shadow_blur_paint(&fill_paint) {
let surface = &mut self.surface;
let last_state = self.states.last().unwrap();
surface.save();
Expand Down Expand Up @@ -331,7 +331,7 @@ impl Context {
}

#[inline(always)]
fn shadow_paint(&self, paint: &Paint) -> Option<Paint> {
fn drop_shadow_paint(&self, paint: &Paint) -> Option<Paint> {
let alpha = paint.get_alpha();
let last_state = self.states.last().unwrap();
let shadow_color = &last_state.shadow_color;
Expand All @@ -346,17 +346,88 @@ impl Context {
{
return None;
}
let mut shadow_paint = paint.clone();
shadow_paint.set_color(
let mut drop_shadow_paint = paint.clone();
let sigma = last_state.shadow_blur / 2f32;
let a = shadow_color.alpha;
let r = shadow_color.red;
let g = shadow_color.green;
let b = shadow_color.blue;
let shadow_effect = ImageFilter::make_drop_shadow(
last_state.shadow_offset_x,
last_state.shadow_offset_y,
sigma,
sigma,
(a as u32) << 24 | (r as u32) << 16 | (g as u32) << 8 | b as u32,
)?;
drop_shadow_paint.set_alpha(shadow_alpha);
drop_shadow_paint.set_image_filter(&shadow_effect);
Some(drop_shadow_paint)
}

#[inline(always)]
fn shadow_blur_paint(&self, paint: &Paint) -> Option<Paint> {
let alpha = paint.get_alpha();
let last_state = self.states.last().unwrap();
let shadow_color = &last_state.shadow_color;
let mut shadow_alpha = shadow_color.alpha;
shadow_alpha = ((shadow_alpha as f32) * (alpha as f32 / 255.0)) as u8;
if shadow_alpha == 0 {
return None;
}
if last_state.shadow_blur == 0f32
&& last_state.shadow_offset_x == 0f32
&& last_state.shadow_offset_y == 0f32
{
return None;
}
let mut drop_shadow_paint = paint.clone();
drop_shadow_paint.set_color(
shadow_color.red,
shadow_color.green,
shadow_color.blue,
shadow_color.alpha,
);
shadow_paint.set_alpha(shadow_alpha);
drop_shadow_paint.set_alpha(shadow_alpha);
let blur_effect = MaskFilter::make_blur(last_state.shadow_blur / 2f32)?;
shadow_paint.set_mask_filter(&blur_effect);
Some(shadow_paint)
drop_shadow_paint.set_mask_filter(&blur_effect);
Some(drop_shadow_paint)
}

#[inline(always)]
fn draw_image(
&mut self,
image: &Image,
sx: f32,
sy: f32,
s_width: f32,
s_height: f32,
dx: f32,
dy: f32,
d_width: f32,
d_height: f32,
) -> Result<()> {
let bitmap = image.bitmap.as_ref().unwrap().bitmap;
let paint = self.fill_paint()?;
if let Some(drop_shadow_paint) = self.drop_shadow_paint(&paint) {
let surface = &mut self.surface;
surface.canvas.draw_image(
bitmap,
sx,
sy,
s_width,
s_height,
dx,
dy,
d_width,
d_height,
&drop_shadow_paint,
);
}
self.surface.canvas.draw_image(
bitmap, sx, sy, s_width, s_height, dx, dy, d_width, d_height, &paint,
);

Ok(())
}

#[inline(always)]
Expand Down Expand Up @@ -647,23 +718,22 @@ fn draw_image(ctx: CallContext) -> Result<JsUndefined> {
let context_2d = ctx.env.unwrap::<Context>(&this)?;
let image_js = ctx.get::<JsObject>(0)?;
let image = ctx.env.unwrap::<Image>(&image_js)?;
let bitmap = image.bitmap.as_ref().unwrap().bitmap;
let image_w = image.bitmap.as_ref().unwrap().width as f32;
let image_h = image.bitmap.as_ref().unwrap().height as f32;

if ctx.length == 3 {
let dx: f64 = ctx.get::<JsNumber>(1)?.try_into()?;
let dy: f64 = ctx.get::<JsNumber>(2)?.try_into()?;
context_2d.surface.canvas.draw_image(
bitmap, 0f32, 0f32, image_w, image_h, dx as f32, dy as f32, image_w, image_h,
);
context_2d.draw_image(
image, 0f32, 0f32, image_w, image_h, dx as f32, dy as f32, image_w, image_h,
)?;
} else if ctx.length == 5 {
let dx: f64 = ctx.get::<JsNumber>(1)?.try_into()?;
let dy: f64 = ctx.get::<JsNumber>(2)?.try_into()?;
let d_width: f64 = ctx.get::<JsNumber>(3)?.try_into()?;
let d_height: f64 = ctx.get::<JsNumber>(4)?.try_into()?;
context_2d.surface.canvas.draw_image(
bitmap,
context_2d.draw_image(
image,
0f32,
0f32,
image_w,
Expand All @@ -672,7 +742,7 @@ fn draw_image(ctx: CallContext) -> Result<JsUndefined> {
dy as f32,
d_width as f32,
d_height as f32,
);
)?;
} else if ctx.length == 9 {
let sx: f64 = ctx.get::<JsNumber>(1)?.try_into()?;
let sy: f64 = ctx.get::<JsNumber>(2)?.try_into()?;
Expand All @@ -682,8 +752,8 @@ fn draw_image(ctx: CallContext) -> Result<JsUndefined> {
let dy: f64 = ctx.get::<JsNumber>(6)?.try_into()?;
let d_width: f64 = ctx.get::<JsNumber>(7)?.try_into()?;
let d_height: f64 = ctx.get::<JsNumber>(8)?.try_into()?;
context_2d.surface.canvas.draw_image(
bitmap,
context_2d.draw_image(
image,
sx as f32,
sy as f32,
s_width as f32,
Expand All @@ -692,7 +762,7 @@ fn draw_image(ctx: CallContext) -> Result<JsUndefined> {
dy as f32,
d_width as f32,
d_height as f32,
);
)?;
}

ctx.env.get_undefined()
Expand Down
Loading

0 comments on commit 8396b93

Please sign in to comment.