diff options
author | Jean-Philippe Andre <jp.andre@samsung.com> | 2017-04-05 15:32:07 +0900 |
---|---|---|
committer | Jean-Philippe Andre <jp.andre@samsung.com> | 2017-04-14 13:57:04 +0900 |
commit | 01a4ecd92c41e9159aafa59754a7be842f5ca0fb (patch) | |
tree | 00aa5876013a003f563bbfe15c87aed4cee0b313 | |
parent | 5467d1eb3eb90126c042e105b93d500f7cf8b323 (diff) |
evas filters: Adjust downscale coordinates to avoid artifacts
This avoids sampling artifacts when moving or resizing a
snapshot object over a region with sharp content (eg. text).
Diffstat (limited to '')
-rw-r--r-- | src/lib/evas/canvas/evas_filter_mixin.c | 4 | ||||
-rw-r--r-- | src/lib/evas/canvas/evas_object_textblock.c | 2 | ||||
-rw-r--r-- | src/lib/evas/filters/evas_filter.c | 64 | ||||
-rw-r--r-- | src/lib/evas/filters/evas_filter_parser.c | 4 | ||||
-rw-r--r-- | src/lib/evas/filters/evas_filter_private.h | 6 | ||||
-rw-r--r-- | src/lib/evas/include/evas_filter.h | 4 | ||||
-rw-r--r-- | src/modules/evas/engines/gl_generic/filters/gl_filter_blend.c | 56 |
7 files changed, 90 insertions, 50 deletions
diff --git a/src/lib/evas/canvas/evas_filter_mixin.c b/src/lib/evas/canvas/evas_filter_mixin.c index d9ada4f1d8..31a7628241 100644 --- a/src/lib/evas/canvas/evas_filter_mixin.c +++ b/src/lib/evas/canvas/evas_filter_mixin.c | |||
@@ -401,7 +401,7 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj, | |||
401 | 401 | ||
402 | if (filter) | 402 | if (filter) |
403 | { | 403 | { |
404 | ok = evas_filter_context_program_reuse(filter, pd->data->chain); | 404 | ok = evas_filter_context_program_reuse(filter, pd->data->chain, X, Y); |
405 | if (!ok) | 405 | if (!ok) |
406 | { | 406 | { |
407 | fcow = FCOW_BEGIN(pd); | 407 | fcow = FCOW_BEGIN(pd); |
@@ -417,7 +417,7 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj, | |||
417 | filter = evas_filter_context_new(obj->layer->evas, do_async, 0); | 417 | filter = evas_filter_context_new(obj->layer->evas, do_async, 0); |
418 | 418 | ||
419 | // Run script | 419 | // Run script |
420 | ok = evas_filter_context_program_use(filter, pd->data->chain, EINA_FALSE); | 420 | ok = evas_filter_context_program_use(filter, pd->data->chain, EINA_FALSE, X, Y); |
421 | if (!filter || !ok) | 421 | if (!filter || !ok) |
422 | { | 422 | { |
423 | ERR("Parsing failed?"); | 423 | ERR("Parsing failed?"); |
diff --git a/src/lib/evas/canvas/evas_object_textblock.c b/src/lib/evas/canvas/evas_object_textblock.c index f65624fb28..abf076c609 100644 --- a/src/lib/evas/canvas/evas_object_textblock.c +++ b/src/lib/evas/canvas/evas_object_textblock.c | |||
@@ -13476,7 +13476,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED, | |||
13476 | ctx = evas_filter_context_new(obj->layer->evas, do_async, ti->gfx_filter); | 13476 | ctx = evas_filter_context_new(obj->layer->evas, do_async, ti->gfx_filter); |
13477 | evas_filter_state_prepare(eo_obj, &state, ti); | 13477 | evas_filter_state_prepare(eo_obj, &state, ti); |
13478 | evas_filter_program_state_set(pgm, &state); | 13478 | evas_filter_program_state_set(pgm, &state); |
13479 | ok = evas_filter_context_program_use(ctx, pgm, EINA_FALSE); | 13479 | ok = evas_filter_context_program_use(ctx, pgm, EINA_FALSE, 0, 0); |
13480 | if (!ok) | 13480 | if (!ok) |
13481 | { | 13481 | { |
13482 | evas_filter_context_destroy(ctx); | 13482 | evas_filter_context_destroy(ctx); |
diff --git a/src/lib/evas/filters/evas_filter.c b/src/lib/evas/filters/evas_filter.c index 2500590634..419c662dc2 100644 --- a/src/lib/evas/filters/evas_filter.c +++ b/src/lib/evas/filters/evas_filter.c | |||
@@ -165,7 +165,7 @@ evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj, | |||
165 | } | 165 | } |
166 | 166 | ||
167 | Eina_Bool | 167 | Eina_Bool |
168 | evas_filter_context_program_reuse(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm) | 168 | evas_filter_context_program_reuse(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm, int x, int y) |
169 | { | 169 | { |
170 | Evas_Filter_Buffer *fb; | 170 | Evas_Filter_Buffer *fb; |
171 | Eina_List *li; | 171 | Eina_List *li; |
@@ -196,7 +196,7 @@ evas_filter_context_program_reuse(Evas_Filter_Context *ctx, Evas_Filter_Program | |||
196 | fb->dirty = EINA_FALSE; | 196 | fb->dirty = EINA_FALSE; |
197 | } | 197 | } |
198 | 198 | ||
199 | return evas_filter_context_program_use(ctx, pgm, EINA_TRUE); | 199 | return evas_filter_context_program_use(ctx, pgm, EINA_TRUE, x, y); |
200 | } | 200 | } |
201 | 201 | ||
202 | static void | 202 | static void |
@@ -691,19 +691,24 @@ evas_filter_command_blur_add_gl(Evas_Filter_Context *ctx, | |||
691 | int rx, int ry, int ox, int oy, int count, | 691 | int rx, int ry, int ox, int oy, int count, |
692 | int R, int G, int B, int A) | 692 | int R, int G, int B, int A) |
693 | { | 693 | { |
694 | Evas_Filter_Command *cmd; | 694 | Evas_Filter_Command *cmd = NULL; |
695 | Evas_Filter_Buffer *dx_in, *dx_out, *dy_in, *dy_out, *tmp = NULL; | 695 | Evas_Filter_Buffer *dx_in, *dx_out, *dy_in, *dy_out, *tmp = NULL; |
696 | int down_x = 1, down_y = 1; | ||
697 | int pad_x = 0, pad_y = 0; | ||
696 | double dx, dy; | 698 | double dx, dy; |
697 | 699 | ||
698 | /* GL blur implementation: | 700 | /* GL blur implementation: |
699 | * - Create intermediate buffer T (variable size) | ||
700 | * - Downscale to buffer T | ||
701 | * - Apply X blur kernel | ||
702 | * - Apply Y blur kernel while scaling up | ||
703 | * | 701 | * |
704 | * - TODO: Fix distortion X vs. Y | 702 | * - Create intermediate buffer T1, T2 |
705 | * - TODO: Calculate best scaline and blur radius | 703 | * - Downscale input to buffer T1 |
706 | * - TODO: Add post-processing? (2D single-pass) | 704 | * - Apply X blur kernel from T1 to T2 |
705 | * - Apply Y blur kernel from T2 back to output | ||
706 | * | ||
707 | * In order to avoid sampling artifacts when moving or resizing a filtered | ||
708 | * snapshot, we make sure that we always sample and scale based on the same | ||
709 | * original pixels positions: | ||
710 | * - Input pixels must be aligned to down_x,down_y boundaries | ||
711 | * - T1/T2 buffer size is up to 1px larger than [input / scale_x,y] | ||
707 | */ | 712 | */ |
708 | 713 | ||
709 | dx = rx; | 714 | dx = rx; |
@@ -714,34 +719,43 @@ evas_filter_command_blur_add_gl(Evas_Filter_Context *ctx, | |||
714 | #if 1 | 719 | #if 1 |
715 | if (type == EVAS_FILTER_BLUR_DEFAULT) | 720 | if (type == EVAS_FILTER_BLUR_DEFAULT) |
716 | { | 721 | { |
717 | int down_x = 1, down_y = 1; | 722 | // Apply downscaling for large enough radii only. |
718 | |||
719 | /* For now, disable scaling - testing perfect gaussian blur until it's | ||
720 | * ready: */ | ||
721 | down_x = 1 << evas_filter_smallest_pow2_larger_than(dx / 2) / 2; | 723 | down_x = 1 << evas_filter_smallest_pow2_larger_than(dx / 2) / 2; |
722 | down_y = 1 << evas_filter_smallest_pow2_larger_than(dy / 2) / 2; | 724 | down_y = 1 << evas_filter_smallest_pow2_larger_than(dy / 2) / 2; |
725 | |||
726 | // Downscaling to max 4 times for perfect picture quality (with | ||
727 | // the standard scaling fragment shader and SHD_SAM22). | ||
723 | if (down_x > 4) down_x = 4; | 728 | if (down_x > 4) down_x = 4; |
724 | if (down_y > 4) down_y = 4; | 729 | if (down_y > 4) down_y = 4; |
725 | 730 | ||
726 | if (down_x > 1 && down_y > 1) | 731 | if (down_x > 1 && down_y > 1) |
727 | { | 732 | { |
728 | tmp = evas_filter_temporary_buffer_get(ctx, | 733 | int ww, hh; |
729 | ceil(ctx->w / down_x), | 734 | |
730 | ceil(ctx->h / down_y), | 735 | pad_x = ctx->x % down_x; |
731 | in->alpha_only, EINA_TRUE); | 736 | pad_y = ctx->y % down_y; |
737 | |||
738 | ww = ceil((double) ctx->w / down_x) + 1; | ||
739 | hh = ceil((double) ctx->h / down_y) + 1; | ||
740 | |||
741 | tmp = evas_filter_temporary_buffer_get(ctx, ww, hh, in->alpha_only, EINA_TRUE); | ||
732 | if (!tmp) goto fail; | 742 | if (!tmp) goto fail; |
733 | 743 | ||
734 | dx = rx / down_x; | 744 | dx /= (double) down_x; |
735 | dy = ry / down_y; | 745 | dy /= (double) down_y; |
736 | 746 | ||
737 | XDBG("Add GL downscale %d (%dx%d) -> %d (%dx%d)", in->id, in->w, in->h, tmp->id, tmp->w, tmp->h); | 747 | XDBG("Add GL downscale %d (%dx%d) -> %d (%dx%d)", in->id, in->w, in->h, tmp->id, tmp->w, tmp->h); |
738 | cmd = _command_new(ctx, EVAS_FILTER_MODE_BLEND, in, NULL, tmp); | 748 | cmd = _command_new(ctx, EVAS_FILTER_MODE_BLEND, in, NULL, tmp); |
739 | if (!cmd) goto fail; | 749 | if (!cmd) goto fail; |
740 | cmd->draw.fillmode = EVAS_FILTER_FILL_MODE_STRETCH_XY; | 750 | cmd->draw.fillmode = EVAS_FILTER_FILL_MODE_STRETCH_XY; |
751 | cmd->draw.scale.down = EINA_TRUE; | ||
752 | cmd->draw.scale.pad_x = pad_x; | ||
753 | cmd->draw.scale.pad_y = pad_y; | ||
754 | cmd->draw.scale.factor_x = down_x; | ||
755 | cmd->draw.scale.factor_y = down_y; | ||
741 | dx_in = tmp; | 756 | dx_in = tmp; |
742 | 757 | ||
743 | tmp = evas_filter_temporary_buffer_get(ctx, ctx->w / down_x, ctx->h / down_y, | 758 | tmp = evas_filter_temporary_buffer_get(ctx, ww, hh, in->alpha_only, EINA_TRUE); |
744 | in->alpha_only, EINA_TRUE); | ||
745 | if (!tmp) goto fail; | 759 | if (!tmp) goto fail; |
746 | dy_out = tmp; | 760 | dy_out = tmp; |
747 | } | 761 | } |
@@ -780,6 +794,7 @@ evas_filter_command_blur_add_gl(Evas_Filter_Context *ctx, | |||
780 | cmd->blur.count = count; | 794 | cmd->blur.count = count; |
781 | } | 795 | } |
782 | 796 | ||
797 | EINA_SAFETY_ON_NULL_RETURN_VAL(cmd, NULL); | ||
783 | if (cmd->output != out) | 798 | if (cmd->output != out) |
784 | { | 799 | { |
785 | XDBG("Add GL upscale %d (%dx%d) -> %d (%dx%d)", | 800 | XDBG("Add GL upscale %d (%dx%d) -> %d (%dx%d)", |
@@ -787,6 +802,11 @@ evas_filter_command_blur_add_gl(Evas_Filter_Context *ctx, | |||
787 | cmd = _command_new(ctx, EVAS_FILTER_MODE_BLEND, cmd->output, NULL, out); | 802 | cmd = _command_new(ctx, EVAS_FILTER_MODE_BLEND, cmd->output, NULL, out); |
788 | if (!cmd) goto fail; | 803 | if (!cmd) goto fail; |
789 | cmd->draw.fillmode = EVAS_FILTER_FILL_MODE_STRETCH_XY; | 804 | cmd->draw.fillmode = EVAS_FILTER_FILL_MODE_STRETCH_XY; |
805 | cmd->draw.scale.down = EINA_FALSE; | ||
806 | cmd->draw.scale.pad_x = pad_x; | ||
807 | cmd->draw.scale.pad_y = pad_y; | ||
808 | cmd->draw.scale.factor_x = down_x; | ||
809 | cmd->draw.scale.factor_y = down_y; | ||
790 | } | 810 | } |
791 | 811 | ||
792 | cmd->draw.ox = ox; | 812 | cmd->draw.ox = ox; |
diff --git a/src/lib/evas/filters/evas_filter_parser.c b/src/lib/evas/filters/evas_filter_parser.c index 60a7ecb476..ccf2806b6a 100644 --- a/src/lib/evas/filters/evas_filter_parser.c +++ b/src/lib/evas/filters/evas_filter_parser.c | |||
@@ -3474,7 +3474,7 @@ _instruction_dump(Evas_Filter_Instruction *instr) | |||
3474 | Eina_Bool | 3474 | Eina_Bool |
3475 | evas_filter_context_program_use(Evas_Filter_Context *ctx, | 3475 | evas_filter_context_program_use(Evas_Filter_Context *ctx, |
3476 | Evas_Filter_Program *pgm, | 3476 | Evas_Filter_Program *pgm, |
3477 | Eina_Bool reuse) | 3477 | Eina_Bool reuse, int object_x, int object_y) |
3478 | { | 3478 | { |
3479 | Evas_Filter_Instruction *instr; | 3479 | Evas_Filter_Instruction *instr; |
3480 | Eina_Bool success = EINA_FALSE; | 3480 | Eina_Bool success = EINA_FALSE; |
@@ -3489,6 +3489,8 @@ evas_filter_context_program_use(Evas_Filter_Context *ctx, | |||
3489 | // Copy current state (size, edje state val, color class, etc...) | 3489 | // Copy current state (size, edje state val, color class, etc...) |
3490 | ctx->w = pgm->state.w; | 3490 | ctx->w = pgm->state.w; |
3491 | ctx->h = pgm->state.h; | 3491 | ctx->h = pgm->state.h; |
3492 | ctx->x = object_x; | ||
3493 | ctx->y = object_y; | ||
3492 | 3494 | ||
3493 | // Create empty context with all required buffers | 3495 | // Create empty context with all required buffers |
3494 | evas_filter_context_clear(ctx, reuse); | 3496 | evas_filter_context_clear(ctx, reuse); |
diff --git a/src/lib/evas/filters/evas_filter_private.h b/src/lib/evas/filters/evas_filter_private.h index 01cda4853a..576cef3cca 100644 --- a/src/lib/evas/filters/evas_filter_private.h +++ b/src/lib/evas/filters/evas_filter_private.h | |||
@@ -125,6 +125,7 @@ struct _Evas_Filter_Context | |||
125 | evas_filter_buffer_scaled_get_func buffer_scaled_get; | 125 | evas_filter_buffer_scaled_get_func buffer_scaled_get; |
126 | 126 | ||
127 | // Variables changing at each run | 127 | // Variables changing at each run |
128 | int x, y; // Position of the object (for GL downscaling of snapshots) | ||
128 | int w, h; // Dimensions of the input/output buffers | 129 | int w, h; // Dimensions of the input/output buffers |
129 | 130 | ||
130 | struct { | 131 | struct { |
@@ -233,6 +234,11 @@ struct _Evas_Filter_Command | |||
233 | int l, r, t, b; | 234 | int l, r, t, b; |
234 | }; | 235 | }; |
235 | } clip; | 236 | } clip; |
237 | struct { | ||
238 | int factor_x, factor_y; | ||
239 | int pad_x, pad_y; | ||
240 | Eina_Bool down; | ||
241 | } scale; | ||
236 | Evas_Filter_Fill_Mode fillmode; | 242 | Evas_Filter_Fill_Mode fillmode; |
237 | Eina_Bool clip_use : 1; | 243 | Eina_Bool clip_use : 1; |
238 | Eina_Bool clip_mode_lrtb : 1; | 244 | Eina_Bool clip_mode_lrtb : 1; |
diff --git a/src/lib/evas/include/evas_filter.h b/src/lib/evas/include/evas_filter.h index 697215978a..ca79b36e1e 100644 --- a/src/lib/evas/include/evas_filter.h +++ b/src/lib/evas/include/evas_filter.h | |||
@@ -147,8 +147,8 @@ void *evas_filter_context_data_get(Evas_Filter_Context *ctx); | |||
147 | Eina_Bool evas_filter_context_async_get(Evas_Filter_Context *ctx); | 147 | Eina_Bool evas_filter_context_async_get(Evas_Filter_Context *ctx); |
148 | void evas_filter_context_size_get(Evas_Filter_Context *ctx, int *w, int *H); | 148 | void evas_filter_context_size_get(Evas_Filter_Context *ctx, int *w, int *H); |
149 | void evas_filter_context_destroy(Evas_Filter_Context *ctx); | 149 | void evas_filter_context_destroy(Evas_Filter_Context *ctx); |
150 | Eina_Bool evas_filter_context_program_use(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm, Eina_Bool reuse); | 150 | Eina_Bool evas_filter_context_program_use(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm, Eina_Bool reuse, int object_x, int object_y); |
151 | Eina_Bool evas_filter_context_program_reuse(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm); | 151 | Eina_Bool evas_filter_context_program_reuse(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm, int x, int y); |
152 | void evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj, Eina_Bool do_async); | 152 | void evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj, Eina_Bool do_async); |
153 | void evas_filter_context_post_run_callback_set(Evas_Filter_Context *ctx, Evas_Filter_Cb cb, void *data); | 153 | void evas_filter_context_post_run_callback_set(Evas_Filter_Context *ctx, Evas_Filter_Cb cb, void *data); |
154 | #define evas_filter_context_autodestroy(ctx) evas_filter_context_post_run_callback_set(ctx, ((Evas_Filter_Cb) evas_filter_context_destroy), ctx) | 154 | #define evas_filter_context_autodestroy(ctx) evas_filter_context_post_run_callback_set(ctx, ((Evas_Filter_Cb) evas_filter_context_destroy), ctx) |
diff --git a/src/modules/evas/engines/gl_generic/filters/gl_filter_blend.c b/src/modules/evas/engines/gl_generic/filters/gl_filter_blend.c index 5f6c84eb8f..3cc1b0f0df 100644 --- a/src/modules/evas/engines/gl_generic/filters/gl_filter_blend.c +++ b/src/modules/evas/engines/gl_generic/filters/gl_filter_blend.c | |||
@@ -12,8 +12,6 @@ _mapped_blend(Evas_Engine_GL_Context *gc, | |||
12 | int row, col, rows, cols; | 12 | int row, col, rows, cols; |
13 | Eina_Bool ret = EINA_TRUE; | 13 | Eina_Bool ret = EINA_TRUE; |
14 | 14 | ||
15 | EINA_SAFETY_ON_FALSE_RETURN_VAL((sx == 0) && (sy == 0), EINA_FALSE); | ||
16 | |||
17 | if (fillmode == EVAS_FILTER_FILL_MODE_NONE) | 15 | if (fillmode == EVAS_FILTER_FILL_MODE_NONE) |
18 | { | 16 | { |
19 | DBG("blend: %d,%d,%d,%d --> %d,%d,%d,%d", sx, sy, sw, sh, dx, dy, sw, sh); | 17 | DBG("blend: %d,%d,%d,%d --> %d,%d,%d,%d", sx, sy, sw, sh, dx, dy, sw, sh); |
@@ -35,7 +33,6 @@ _mapped_blend(Evas_Engine_GL_Context *gc, | |||
35 | else if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_X) | 33 | else if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_X) |
36 | { | 34 | { |
37 | cols = 0; | 35 | cols = 0; |
38 | dx = 0; | ||
39 | } | 36 | } |
40 | else | 37 | else |
41 | { | 38 | { |
@@ -58,7 +55,6 @@ _mapped_blend(Evas_Engine_GL_Context *gc, | |||
58 | else if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_Y) | 55 | else if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_Y) |
59 | { | 56 | { |
60 | rows = 0; | 57 | rows = 0; |
61 | dy = 0; | ||
62 | } | 58 | } |
63 | else | 59 | else |
64 | { | 60 | { |
@@ -95,9 +91,10 @@ _mapped_blend(Evas_Engine_GL_Context *gc, | |||
95 | src_y = 0; | 91 | src_y = 0; |
96 | if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_Y) | 92 | if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_Y) |
97 | { | 93 | { |
94 | src_y = sy; | ||
98 | src_h = sh; | 95 | src_h = sh; |
96 | dst_y = dy; | ||
99 | dst_h = dh; | 97 | dst_h = dh; |
100 | dst_y = 0; | ||
101 | } | 98 | } |
102 | else | 99 | else |
103 | { | 100 | { |
@@ -133,9 +130,10 @@ _mapped_blend(Evas_Engine_GL_Context *gc, | |||
133 | src_x = 0; | 130 | src_x = 0; |
134 | if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_X) | 131 | if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_X) |
135 | { | 132 | { |
133 | src_x = sx; | ||
136 | src_w = sw; | 134 | src_w = sw; |
135 | dst_x = dx; | ||
137 | dst_w = dw; | 136 | dst_w = dw; |
138 | dst_x = 0; | ||
139 | } | 137 | } |
140 | else | 138 | else |
141 | { | 139 | { |
@@ -163,7 +161,7 @@ _gl_filter_blend(Render_Engine_GL_Generic *re, Evas_Filter_Command *cmd) | |||
163 | Evas_Engine_GL_Context *gc; | 161 | Evas_Engine_GL_Context *gc; |
164 | Evas_GL_Image *image, *surface; | 162 | Evas_GL_Image *image, *surface; |
165 | RGBA_Draw_Context *dc_save; | 163 | RGBA_Draw_Context *dc_save; |
166 | int src_w, src_h, dst_w, dst_h; | 164 | int src_w, src_h, dst_w, dst_h, src_x, src_y, dst_x, dst_y; |
167 | 165 | ||
168 | DEBUG_TIME_BEGIN(); | 166 | DEBUG_TIME_BEGIN(); |
169 | 167 | ||
@@ -188,40 +186,54 @@ _gl_filter_blend(Render_Engine_GL_Generic *re, Evas_Filter_Command *cmd) | |||
188 | if ((cmd->draw.fillmode == EVAS_FILTER_FILL_MODE_STRETCH_XY) && | 186 | if ((cmd->draw.fillmode == EVAS_FILTER_FILL_MODE_STRETCH_XY) && |
189 | ((image->w != surface->w) || (image->h != surface->h))) | 187 | ((image->w != surface->w) || (image->h != surface->h))) |
190 | { | 188 | { |
191 | int scale_w, scale_h; | 189 | double scale_w, scale_h; |
190 | int pad_x, pad_y; | ||
192 | 191 | ||
193 | if ((image->w >= surface->w) || | 192 | pad_x = cmd->draw.scale.pad_x; |
194 | (image->h >= surface->h)) | 193 | pad_y = cmd->draw.scale.pad_y; |
194 | scale_w = MAX(cmd->draw.scale.factor_x, 1); | ||
195 | scale_h = MAX(cmd->draw.scale.factor_y, 1); | ||
196 | |||
197 | if (cmd->draw.scale.down) | ||
195 | { | 198 | { |
196 | scale_w = image->w / surface->w; | 199 | src_x = -pad_x; |
197 | scale_h = image->h / surface->h; | 200 | src_y = -pad_y; |
198 | src_w = ((image->w + (scale_w - 1)) / scale_w) * scale_w; | 201 | src_w = (ceil(image->w / scale_w) + 1) * scale_w; |
199 | src_h = ((image->h + (scale_h - 1)) / scale_h) * scale_h; | 202 | src_h = (ceil(image->h / scale_h) + 1) * scale_h; |
200 | dst_w = surface->w; | 203 | dst_x = 0; |
201 | dst_h = surface->h; | 204 | dst_y = 0; |
205 | dst_w = src_w / scale_w; | ||
206 | dst_h = src_h / scale_h; | ||
202 | } | 207 | } |
203 | else | 208 | else |
204 | { | 209 | { |
205 | scale_w = surface->w / image->w; | 210 | src_x = 0; |
206 | scale_h = surface->h / image->h; | 211 | src_y = 0; |
207 | src_w = image->w; | 212 | src_w = image->w; |
208 | src_h = image->h; | 213 | src_h = image->h; |
209 | dst_w = ((surface->w + (scale_w - 1)) / scale_w) * scale_w; | 214 | dst_x = cmd->draw.ox - pad_x; |
210 | dst_h = ((surface->h + (scale_h - 1)) / scale_h) * scale_h; | 215 | dst_y = cmd->draw.oy - pad_y; |
216 | dst_w = (ceil(surface->w / scale_w) + 1) * scale_w; | ||
217 | dst_h = (ceil(surface->h / scale_h) + 1) * scale_h; | ||
211 | } | 218 | } |
212 | } | 219 | } |
213 | else | 220 | else |
214 | { | 221 | { |
222 | src_x = 0; | ||
223 | src_y = 0; | ||
215 | src_w = image->w; | 224 | src_w = image->w; |
216 | src_h = image->h; | 225 | src_h = image->h; |
226 | dst_x = cmd->draw.ox; | ||
227 | dst_y = cmd->draw.oy; | ||
217 | dst_w = surface->w; | 228 | dst_w = surface->w; |
218 | dst_h = surface->h; | 229 | dst_h = surface->h; |
219 | } | 230 | } |
220 | 231 | ||
221 | DBG("blend %d @%p -> %d @%p", cmd->input->id, cmd->input->buffer, | 232 | DBG("blend %d @%p -> %d @%p", cmd->input->id, cmd->input->buffer, |
222 | cmd->output->id, cmd->output->buffer); | 233 | cmd->output->id, cmd->output->buffer); |
223 | _mapped_blend(gc, image, cmd->draw.fillmode, 0, 0, src_w, src_h, | 234 | _mapped_blend(gc, image, cmd->draw.fillmode, |
224 | cmd->draw.ox, cmd->draw.oy, dst_w, dst_h); | 235 | src_x, src_y, src_w, src_h, |
236 | dst_x, dst_y, dst_w, dst_h); | ||
225 | 237 | ||
226 | evas_common_draw_context_free(gc->dc); | 238 | evas_common_draw_context_free(gc->dc); |
227 | gc->dc = dc_save; | 239 | gc->dc = dc_save; |