From cca66b9ec4e494c1d919bff0f71a820d8afab1fa Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:24:48 +0200 Subject: Adding upstream version 1.2.2. Signed-off-by: Daniel Baumann --- src/display/nr-filter-slot.cpp | 301 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 src/display/nr-filter-slot.cpp (limited to 'src/display/nr-filter-slot.cpp') diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp new file mode 100644 index 0000000..4d9dc23 --- /dev/null +++ b/src/display/nr-filter-slot.cpp @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * A container class for filter slots. Allows for simple getting and + * setting images in filter slots without having to bother with + * table indexes and such. + * + * Author: + * Niko Kiirala + * + * Copyright (C) 2006,2007 Niko Kiirala + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include +#include + +#include <2geom/transforms.h> +#include "display/cairo-utils.h" +#include "display/drawing-context.h" +#include "display/nr-filter-types.h" +#include "display/nr-filter-gaussian.h" +#include "display/nr-filter-slot.h" +#include "display/nr-filter-units.h" + +namespace Inkscape { +namespace Filters { + +FilterSlot::FilterSlot(DrawingItem *item, DrawingContext *bgdc, + DrawingContext &graphic, FilterUnits const &u) + : _item(item) + , _source_graphic(graphic.rawTarget()) + , _background_ct(bgdc ? bgdc->raw() : nullptr) + , _source_graphic_area(graphic.targetLogicalBounds().roundOutwards()) // fixme + , _background_area(bgdc ? bgdc->targetLogicalBounds().roundOutwards() : Geom::IntRect()) // fixme + , _units(u) + , _last_out(NR_FILTER_SOURCEGRAPHIC) + , filterquality(FILTER_QUALITY_BEST) + , blurquality(BLUR_QUALITY_BEST) +{ + using Geom::X; + using Geom::Y; + + // compute slot bbox + Geom::Affine trans = _units.get_matrix_display2pb(); + Geom::Rect bbox_trans = graphic.targetLogicalBounds() * trans; + Geom::Point min = bbox_trans.min(); + _slot_x = min[X]; + _slot_y = min[Y]; + + if (trans.isTranslation()) { + _slot_w = _source_graphic_area.width(); + _slot_h = _source_graphic_area.height(); + } else { + _slot_w = ceil(bbox_trans.width()); + _slot_h = ceil(bbox_trans.height()); + } +} + +FilterSlot::~FilterSlot() +{ + for (auto & _slot : _slots) { + cairo_surface_destroy(_slot.second); + } +} + +cairo_surface_t *FilterSlot::getcairo(int slot_nr) +{ + if (slot_nr == NR_FILTER_SLOT_NOT_SET) + slot_nr = _last_out; + + SlotMap::iterator s = _slots.find(slot_nr); + + /* If we didn't have the specified image, but we could create it + * from the other information we have, let's do that */ + if (s == _slots.end() + && (slot_nr == NR_FILTER_SOURCEGRAPHIC + || slot_nr == NR_FILTER_SOURCEALPHA + || slot_nr == NR_FILTER_BACKGROUNDIMAGE + || slot_nr == NR_FILTER_BACKGROUNDALPHA + || slot_nr == NR_FILTER_FILLPAINT + || slot_nr == NR_FILTER_STROKEPAINT)) + { + switch (slot_nr) { + case NR_FILTER_SOURCEGRAPHIC: { + cairo_surface_t *tr = _get_transformed_source_graphic(); + // Assume all source graphics are sRGB + set_cairo_surface_ci( tr, SP_CSS_COLOR_INTERPOLATION_SRGB ); + _set_internal(NR_FILTER_SOURCEGRAPHIC, tr); + cairo_surface_destroy(tr); + } break; + case NR_FILTER_BACKGROUNDIMAGE: { + cairo_surface_t *bg = _get_transformed_background(); + // Assume all backgrounds are sRGB + set_cairo_surface_ci( bg, SP_CSS_COLOR_INTERPOLATION_SRGB ); + _set_internal(NR_FILTER_BACKGROUNDIMAGE, bg); + cairo_surface_destroy(bg); + } break; + case NR_FILTER_SOURCEALPHA: { + cairo_surface_t *src = getcairo(NR_FILTER_SOURCEGRAPHIC); + cairo_surface_t *alpha = ink_cairo_extract_alpha(src); + _set_internal(NR_FILTER_SOURCEALPHA, alpha); + cairo_surface_destroy(alpha); + } break; + case NR_FILTER_BACKGROUNDALPHA: { + cairo_surface_t *src = getcairo(NR_FILTER_BACKGROUNDIMAGE); + cairo_surface_t *ba = ink_cairo_extract_alpha(src); + _set_internal(NR_FILTER_BACKGROUNDALPHA, ba); + cairo_surface_destroy(ba); + } break; + case NR_FILTER_FILLPAINT: //TODO + case NR_FILTER_STROKEPAINT: //TODO + default: + break; + } + s = _slots.find(slot_nr); + } + + if (s == _slots.end()) { + // create empty surface + cairo_surface_t *empty = cairo_surface_create_similar( + _source_graphic, cairo_surface_get_content(_source_graphic), + _slot_w, _slot_h); + _set_internal(slot_nr, empty); + cairo_surface_destroy(empty); + s = _slots.find(slot_nr); + } + return s->second; +} + +cairo_surface_t *FilterSlot::_get_transformed_source_graphic() +{ + Geom::Affine trans = _units.get_matrix_display2pb(); + + if (trans.isTranslation()) { + cairo_surface_reference(_source_graphic); + return _source_graphic; + } + + cairo_surface_t *tsg = cairo_surface_create_similar( + _source_graphic, cairo_surface_get_content(_source_graphic), + _slot_w, _slot_h); + cairo_t *tsg_ct = cairo_create(tsg); + + cairo_translate(tsg_ct, -_slot_x, -_slot_y); + ink_cairo_transform(tsg_ct, trans); + cairo_translate(tsg_ct, _source_graphic_area.left(), _source_graphic_area.top()); + cairo_set_source_surface(tsg_ct, _source_graphic, 0, 0); + cairo_set_operator(tsg_ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(tsg_ct); + cairo_destroy(tsg_ct); + + return tsg; +} + +cairo_surface_t *FilterSlot::_get_transformed_background() +{ + Geom::Affine trans = _units.get_matrix_display2pb(); + + cairo_surface_t *tbg; + + if (_background_ct) { + cairo_surface_t *bg = cairo_get_group_target(_background_ct); + tbg = cairo_surface_create_similar( + bg, cairo_surface_get_content(bg), + _slot_w, _slot_h); + cairo_t *tbg_ct = cairo_create(tbg); + + cairo_translate(tbg_ct, -_slot_x, -_slot_y); + ink_cairo_transform(tbg_ct, trans); + cairo_translate(tbg_ct, _background_area.left(), _background_area.top()); + cairo_set_source_surface(tbg_ct, bg, 0, 0); + cairo_set_operator(tbg_ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(tbg_ct); + cairo_destroy(tbg_ct); + } else { + tbg = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, _slot_w, _slot_h); + } + + return tbg; +} + +cairo_surface_t *FilterSlot::get_result(int res) +{ + cairo_surface_t *result = getcairo(res); + + Geom::Affine trans = _units.get_matrix_pb2display(); + if (trans.isIdentity()) { + cairo_surface_reference(result); + return result; + } + + cairo_surface_t *r = cairo_surface_create_similar(_source_graphic, + cairo_surface_get_content(_source_graphic), + _source_graphic_area.width(), + _source_graphic_area.height()); + copy_cairo_surface_ci( result, r ); + cairo_t *r_ct = cairo_create(r); + + cairo_translate(r_ct, -_source_graphic_area.left(), -_source_graphic_area.top()); + ink_cairo_transform(r_ct, trans); + cairo_translate(r_ct, _slot_x, _slot_y); + cairo_set_source_surface(r_ct, result, 0, 0); + cairo_set_operator(r_ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(r_ct); + cairo_destroy(r_ct); + + return r; +} + +void FilterSlot::_set_internal(int slot_nr, cairo_surface_t *surface) +{ + // destroy after referencing + // this way assigning a surface to a slot it already occupies will not cause errors + cairo_surface_reference(surface); + + SlotMap::iterator s = _slots.find(slot_nr); + if (s != _slots.end()) { + cairo_surface_destroy(s->second); + } + + _slots[slot_nr] = surface; +} + +void FilterSlot::set(int slot_nr, cairo_surface_t *surface) +{ + g_return_if_fail(surface != nullptr); + + if (slot_nr == NR_FILTER_SLOT_NOT_SET) + slot_nr = NR_FILTER_UNNAMED_SLOT; + + _set_internal(slot_nr, surface); + _last_out = slot_nr; +} + +void FilterSlot::set_primitive_area(int slot_nr, Geom::Rect &area) +{ + if (slot_nr == NR_FILTER_SLOT_NOT_SET) + slot_nr = NR_FILTER_UNNAMED_SLOT; + + _primitiveAreas[slot_nr] = area; +} + +Geom::Rect FilterSlot::get_primitive_area(int slot_nr) +{ + if (slot_nr == NR_FILTER_SLOT_NOT_SET) + slot_nr = _last_out; + + PrimitiveAreaMap::iterator s = _primitiveAreas.find(slot_nr); + + if (s == _primitiveAreas.end()) { + return *(_units.get_filter_area()); + } + return s->second; +} + +int FilterSlot::get_slot_count() +{ + return _slots.size(); +} + +void FilterSlot::set_quality(FilterQuality const q) { + filterquality = q; +} + +void FilterSlot::set_blurquality(int const q) { + blurquality = q; +} + +int FilterSlot::get_blurquality() { + return blurquality; +} + +void FilterSlot::set_device_scale(int const s) { + device_scale = s; +} + +int FilterSlot::get_device_scale() { + return device_scale; +} + +Geom::Rect FilterSlot::get_slot_area() const { + Geom::Point p(_slot_x, _slot_y); + Geom::Point dim(_slot_w, _slot_h); + Geom::Rect r(p, p+dim); + return r; +} + +} /* namespace Filters */ +} /* namespace Inkscape */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : -- cgit v1.2.3