summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2013-09-26 22:42:32 +0000
committerKrzysztof Kosiński <tweenk.pl@gmail.com>2013-09-26 22:42:32 +0000
commit81209cb6fe83ccf8cb1244fe63f93361f68cc7c0 (patch)
tree8edcd48c973f702e091b1e8bcd1887c0023fdee7 /src
parentThe downscaling fix is already in Cairo trunk. (diff)
downloadinkscape-81209cb6fe83ccf8cb1244fe63f93361f68cc7c0.tar.gz
inkscape-81209cb6fe83ccf8cb1244fe63f93361f68cc7c0.zip
Use Cairo 1.10 blend operators to render feBlend
(bzr r12600)
Diffstat (limited to 'src')
-rw-r--r--src/display/nr-filter-blend.cpp164
1 files changed, 30 insertions, 134 deletions
diff --git a/src/display/nr-filter-blend.cpp b/src/display/nr-filter-blend.cpp
index a08191f67..bff7405b7 100644
--- a/src/display/nr-filter-blend.cpp
+++ b/src/display/nr-filter-blend.cpp
@@ -1,6 +1,6 @@
-/*
+/** @file
* SVG feBlend renderer
- *
+ *//*
* "This filter composites two objects together using commonly used
* imaging software blending modes. It performs a pixel-wise combination
* of two input images."
@@ -9,6 +9,7 @@
* Authors:
* Niko Kiirala <niko@kiirala.com>
* Jasper van de Gronde <th.v.d.gronde@hccnet.nl>
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
*
* Copyright (C) 2007-2008 authors
*
@@ -30,20 +31,6 @@
namespace Inkscape {
namespace Filters {
-/*
- * From http://www.w3.org/TR/SVG11/filters.html#feBlend
- *
- * For all feBlend modes, the result opacity is computed as follows:
- * qr = 1 - (1-qa)*(1-qb)
- *
- * For the compositing formulas below, the following definitions apply:
- * cr = Result color (RGB) - premultiplied
- * qa = Opacity value at a given pixel for image A
- * qb = Opacity value at a given pixel for image B
- * ca = Color (RGB) at a given pixel for image A - premultiplied
- * cb = Color (RGB) at a given pixel for image B - premultiplied
- */
-
FilterBlend::FilterBlend()
: _blend_mode(BLEND_NORMAL),
_input2(NR_FILTER_SLOT_NOT_SET)
@@ -56,91 +43,6 @@ FilterPrimitive * FilterBlend::create() {
FilterBlend::~FilterBlend()
{}
-// cr = (1-qa)*cb + (1-qb)*ca + ca*cb
-struct BlendMultiply {
- guint32 operator()(guint32 in1, guint32 in2)
- {
- EXTRACT_ARGB32(in1, aa, ra, ga, ba)
- EXTRACT_ARGB32(in2, ab, rb, gb, bb)
-
- guint32 ao = 255*255 - (255-aa)*(255-ab); ao = (ao + 127) / 255;
- guint32 ro = (255-aa)*rb + (255-ab)*ra + ra*rb; ro = (ro + 127) / 255;
- guint32 go = (255-aa)*gb + (255-ab)*ga + ga*gb; go = (go + 127) / 255;
- guint32 bo = (255-aa)*bb + (255-ab)*ba + ba*bb; bo = (bo + 127) / 255;
-
- ASSEMBLE_ARGB32(pxout, ao, ro, go, bo)
- return pxout;
- }
-};
-
-// cr = cb + ca - ca * cb
-struct BlendScreen {
- guint32 operator()(guint32 in1, guint32 in2)
- {
- EXTRACT_ARGB32(in1, aa, ra, ga, ba)
- EXTRACT_ARGB32(in2, ab, rb, gb, bb)
-
- guint32 ao = 255*255 - (255-aa)*(255-ab); ao = (ao + 127) / 255;
- guint32 ro = 255*(rb + ra) - ra * rb; ro = (ro + 127) / 255;
- guint32 go = 255*(gb + ga) - ga * gb; go = (go + 127) / 255;
- guint32 bo = 255*(bb + ba) - ba * bb; bo = (bo + 127) / 255;
-
- ASSEMBLE_ARGB32(pxout, ao, ro, go, bo)
- return pxout;
- }
-};
-
-// cr = Min ((1 - qa) * cb + ca, (1 - qb) * ca + cb)
-struct BlendDarken {
- guint32 operator()(guint32 in1, guint32 in2)
- {
- EXTRACT_ARGB32(in1, aa, ra, ga, ba)
- EXTRACT_ARGB32(in2, ab, rb, gb, bb)
-
- guint32 ao = 255*255 - (255-aa)*(255-ab); ao = (ao + 127) / 255;
- guint32 ro = std::min((255-aa)*rb + 255*ra, (255-ab)*ra + 255*rb); ro = (ro + 127) / 255;
- guint32 go = std::min((255-aa)*gb + 255*ga, (255-ab)*ga + 255*gb); go = (go + 127) / 255;
- guint32 bo = std::min((255-aa)*bb + 255*ba, (255-ab)*ba + 255*bb); bo = (bo + 127) / 255;
-
- ASSEMBLE_ARGB32(pxout, ao, ro, go, bo)
- return pxout;
- }
-};
-
-// cr = Max ((1 - qa) * cb + ca, (1 - qb) * ca + cb)
-struct BlendLighten {
- guint32 operator()(guint32 in1, guint32 in2)
- {
- EXTRACT_ARGB32(in1, aa, ra, ga, ba)
- EXTRACT_ARGB32(in2, ab, rb, gb, bb)
-
- guint32 ao = 255*255 - (255-aa)*(255-ab); ao = (ao + 127) / 255;
- guint32 ro = std::max((255-aa)*rb + 255*ra, (255-ab)*ra + 255*rb); ro = (ro + 127) / 255;
- guint32 go = std::max((255-aa)*gb + 255*ga, (255-ab)*ga + 255*gb); go = (go + 127) / 255;
- guint32 bo = std::max((255-aa)*bb + 255*ba, (255-ab)*ba + 255*bb); bo = (bo + 127) / 255;
-
- ASSEMBLE_ARGB32(pxout, ao, ro, go, bo)
- return pxout;
- }
-};
-
-/*
-struct BlendAlpha
-static inline void blend_alpha(guint32 in1, guint32 in2, guint32 *out)
-{
- EXTRACT_ARGB32(in1, a1, a2, a3, a4);
- EXTRACT_ARGB32(in2, b1, b2, b3, b4);
-
- guint32 o1 = 255*255 - (255-a1)*(255-b1); o1 = (o1+127) / 255;
- guint32 o2 = 255*255 - (255-a2)*(255-b2); o2 = (o2+127) / 255;
- guint32 o3 = 255*255 - (255-a3)*(255-b3); o3 = (o3+127) / 255;
- guint32 o4 = 255*255 - (255-a4)*(255-b4); o4 = (o4+127) / 255;
-
- ASSEMBLE_ARGB32(pxout, o1, o2, o3, o4);
- *out = pxout;
-}
-*/
-
void FilterBlend::render_cairo(FilterSlot &slot)
{
cairo_surface_t *input1 = slot.getcairo(_input);
@@ -161,41 +63,35 @@ void FilterBlend::render_cairo(FilterSlot &slot)
cairo_surface_t *out = ink_cairo_surface_create_output(input1, input2);
set_cairo_surface_ci( out, ci_fp );
- cairo_content_t ct1 = cairo_surface_get_content(input1);
- cairo_content_t ct2 = cairo_surface_get_content(input2);
- if ((ct1 == CAIRO_CONTENT_ALPHA && ct2 == CAIRO_CONTENT_ALPHA)
- || _blend_mode == BLEND_NORMAL)
- {
- ink_cairo_surface_blit(input2, out);
- cairo_t *out_ct = cairo_create(out);
- cairo_set_source_surface(out_ct, input1, 0, 0);
- cairo_paint(out_ct);
- cairo_destroy(out_ct);
- } else {
- // blend mode != normal and at least 1 surface is not pure alpha
-
- // TODO: convert to Cairo blending operators once we start using the 1.10 series
- switch (_blend_mode) {
- case BLEND_MULTIPLY:
- ink_cairo_surface_blend(input1, input2, out, BlendMultiply());
- break;
- case BLEND_SCREEN:
- ink_cairo_surface_blend(input1, input2, out, BlendScreen());
- break;
- case BLEND_DARKEN:
- ink_cairo_surface_blend(input1, input2, out, BlendDarken());
- break;
- case BLEND_LIGHTEN:
- ink_cairo_surface_blend(input1, input2, out, BlendLighten());
- break;
- case BLEND_NORMAL:
- default:
- // this was handled before
- g_assert_not_reached();
- break;
- }
+ ink_cairo_surface_blit(input2, out);
+ cairo_t *out_ct = cairo_create(out);
+ cairo_set_source_surface(out_ct, input1, 0, 0);
+
+ // All of the blend modes are implemented in Cairo as of 1.10.
+ // For a detailed description, see:
+ // http://cairographics.org/operators/
+ switch (_blend_mode) {
+ case BLEND_MULTIPLY:
+ cairo_set_operator(out_ct, CAIRO_OPERATOR_MULTIPLY);
+ break;
+ case BLEND_SCREEN:
+ cairo_set_operator(out_ct, CAIRO_OPERATOR_SCREEN);
+ break;
+ case BLEND_DARKEN:
+ cairo_set_operator(out_ct, CAIRO_OPERATOR_DARKEN);
+ break;
+ case BLEND_LIGHTEN:
+ cairo_set_operator(out_ct, CAIRO_OPERATOR_LIGHTEN);
+ break;
+ case BLEND_NORMAL:
+ default:
+ cairo_set_operator(out_ct, CAIRO_OPERATOR_OVER);
+ break;
}
+ cairo_paint(out_ct);
+ cairo_destroy(out_ct);
+
slot.set(_output, out);
cairo_surface_destroy(out);
}