From cfb5fa826062314dac912b3627f932aab8250988 Mon Sep 17 00:00:00 2001 From: kiirala Date: Tue, 18 Jul 2006 10:35:54 +0000 Subject: [PATCH] Added a bunch of comments to filter effects rendering code --- src/display/nr-filter-primitive.cpp | 3 ++ src/display/nr-filter-slot.h | 25 ++++++++++++++ src/display/nr-filter.cpp | 40 +++++++++++++++++++++- src/display/pixblock-scaler.cpp | 53 +++++++++++++++++++++++++++-- src/display/pixblock-scaler.h | 17 +++++++++ 5 files changed, 135 insertions(+), 3 deletions(-) diff --git a/src/display/nr-filter-primitive.cpp b/src/display/nr-filter-primitive.cpp index 556812db5..9ea721d3b 100644 --- a/src/display/nr-filter-primitive.cpp +++ b/src/display/nr-filter-primitive.cpp @@ -23,6 +23,8 @@ FilterPrimitive::FilterPrimitive() _input = NR_FILTER_SLOT_NOT_SET; _output = NR_FILTER_SLOT_NOT_SET; + // These defaults are according to SVG standard. + // NB: SVGLength.set takes prescaled percent values: 1 means 100% _region_x.set(SVGLength::PERCENT, 0, 0); _region_y.set(SVGLength::PERCENT, 0, 0); _region_width.set(SVGLength::PERCENT, 1, 0); @@ -34,6 +36,7 @@ FilterPrimitive::~FilterPrimitive() // Nothing to do here } +/** Wrapper function for rendering with C-style matrices. */ int FilterPrimitive::render(FilterSlot &slot, NRMatrix const *trans) { if(trans) { return this->render(slot, *trans); diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h index 74cf7e003..13ce1afe2 100644 --- a/src/display/nr-filter-slot.h +++ b/src/display/nr-filter-slot.h @@ -20,13 +20,35 @@ namespace NR { class FilterSlot { public: + /** Creates a new FilterSlot object, with two slots. */ FilterSlot(); + /** Creates a new FilterSlot object, with specified amount of slots */ FilterSlot(int slots); + /** Destroys the FilterSlot object and all its contents */ ~FilterSlot(); + /** Returns the pixblock in specified slot. + * Parameter 'slot' may be either an positive integer or one of + * pre-defined filter slot types: NR_FILTER_SLOT_NOT_SET, + * NR_FILTER_SOURCEGRAPHIC, NR_FILTER_SOURCEALPHA, + * NR_FILTER_BACKGROUNDIMAGE, NR_FILTER_BACKGROUNDALPHA, + * NR_FILTER_FILLPAINT, NR_FILTER_SOURCEPAINT. + * If the defined filter slot is not set before, this function + * returns NULL. Also, that filter slot is created in process. + */ NRPixBlock *get(int slot); + + /** Sets or re-sets the pixblock associated with given slot. + * If there was a pixblock already assigned with this slot, + * that pixblock is destroyed. + * Pixblocks passed to this function should be considered + * managed by this FilterSlot object. + * Pixblocks passed to this function should be reserved with + * c++ -style new-operator. + */ void set(int slot, NRPixBlock *pb); + /** Returns the number of slots in use. */ int get_slot_count(); private: @@ -36,6 +58,9 @@ private: int _last_out; + /** Returns the table index of given slot. If that slot dows not exist, + * it is created. Table index can be used to read the correct + * pixblock from _slot */ int _get_index(int slot); }; diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index 6c57f3200..db1e9d8db 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -54,13 +54,19 @@ Filter::Filter(int n) void Filter::_common_init() { _slot_count = 1; + // Having "not set" here as value means the output of last filter + // primitive will be used as output of this filter _output_slot = NR_FILTER_SLOT_NOT_SET; + // These are the default values for filter region, + // as specified in SVG standard + // NB: SVGLength.set takes prescaled percent values: -.10 means -10% _region_x.set(SVGLength::PERCENT, -.10, 0); _region_y.set(SVGLength::PERCENT, -.10, 0); _region_width.set(SVGLength::PERCENT, 1.20, 0); _region_height.set(SVGLength::PERCENT, 1.20, 0); + // Filter resolution, negative value here stands for "automatic" _x_pixels = -1.0; _y_pixels = -1.0; @@ -80,6 +86,9 @@ int Filter::render(NRArenaItem const *item, NRPixBlock *pb) Matrix trans = *item->ctm; FilterSlot slot(_slot_count); NRPixBlock *in = new NRPixBlock; + + // First, if filter resolution is not set to automatic, we should + // scale the input image to correct resolution if (_x_pixels >= 0) { /* If filter resolution is zero, the object should not be rendered */ if (_x_pixels == 0 || _y_pixels == 0) { @@ -89,8 +98,14 @@ int Filter::render(NRArenaItem const *item, NRPixBlock *pb) memset(NR_PIXBLOCK_PX(pb), 0, size); return 0; } + // Resolution is specified as pixel length of our internal buffer. + // Though, we might not be rendering the whole object at time, + // so we need to calculate the correct pixel size int x_len = (int)round(((pb->area.x1 - pb->area.x0) * _x_pixels) / (item->bbox.x1 - item->bbox.x0)); if (x_len < 1) x_len = 1; + // If y-resolution is also set, count y-area in the same way as x-area + // Otherwise, make y-area so, that aspect ratio of input pixblock and + // internal pixblock are the same. int y_len; if (_y_pixels > 0) { y_len = (int)round(((pb->area.y1 - pb->area.y0) * _y_pixels) / (item->bbox.y1 - item->bbox.y0)); @@ -104,6 +119,7 @@ int Filter::render(NRArenaItem const *item, NRPixBlock *pb) y_len / (double)(pb->area.y1 - pb->area.y0)); trans *= res_scaling; } else { + // If filter resolution is automatic, just make copy of input image nr_pixblock_setup_fast(in, pb->mode, pb->area.x0, pb->area.y0, pb->area.x1, pb->area.y1, true); @@ -112,27 +128,38 @@ int Filter::render(NRArenaItem const *item, NRPixBlock *pb) slot.set(NR_FILTER_SOURCEGRAPHIC, in); in = NULL; // in is now handled by FilterSlot, we should not touch it + // TODO: loop through the primitives and render them one at a time _primitive[0]->render(slot, trans); NRPixBlock *out = slot.get(_output_slot); + // Clear the pixblock, where the output will be put + // -> the original image does not show through int size = (pb->area.x1 - pb->area.x0) * (pb->area.y1 - pb->area.y0) * NR_PIXBLOCK_BPP(pb); memset(NR_PIXBLOCK_PX(pb), 0, size); - + + // If the filter resolution is automatic, just copy our final image + // to output pixblock, otherwise use bicubic scaling if (_x_pixels < 0) { nr_blit_pixblock_pixblock(pb, out); } else { scale_bicubic(pb, out); } + // Take note of the amount of used image slots + // -> next time this filter is rendered, we can reserve enough slots + // immediately _slot_count = slot.get_slot_count(); return 0; } int Filter::get_enlarge(Matrix const &m) { + // Just sum the enlargement factor of all filter elements. + // TODO: this both sucks and blows for filters like feOffset + // -> ditch this method and design a better one... int enlarge = 0; for ( int i = 0 ; i < _primitive_count ; i++ ) { if(_primitive[i]) enlarge += _primitive[i]->get_enlarge(m); @@ -182,11 +209,17 @@ void Filter::bbox_enlarge(NRRectL &bbox) } } +/* Constructor table holds pointers to static methods returning filter + * primitives. This table is indexed with FilterPrimitiveType, so that + * for example method in _constructor[NR_FILTER_GAUSSIANBLUR] + * returns a filter object of type NR::FilterGaussian. + */ typedef FilterPrimitive*(*FilterConstructor)(); static FilterConstructor _constructor[NR_FILTER_ENDPRIMITIVETYPE]; void Filter::_create_constructor_table() { + // Constructor table won't change in run-time, so no need to recreate static bool created = false; if(created) return; @@ -207,8 +240,13 @@ void Filter::_create_constructor_table() _constructor[NR_FILTER_SPECULARLIGHTING] = NULL; _constructor[NR_FILTER_TILE] = NULL; _constructor[NR_FILTER_TURBULENCE] = NULL; + created = true; } +/** Helper method for enlarging table of filter primitives. When new + * primitives are added, but we have no space for them, this function + * makes some more space. + */ void Filter::_enlarge_primitive_table() { FilterPrimitive **new_tbl = new FilterPrimitive*[_primitive_table_size * 2]; for (int i = 0 ; i < _primitive_count ; i++) { diff --git a/src/display/pixblock-scaler.cpp b/src/display/pixblock-scaler.cpp index 3b8461383..3be52c3f3 100644 --- a/src/display/pixblock-scaler.cpp +++ b/src/display/pixblock-scaler.cpp @@ -1,5 +1,16 @@ #define __NR_PIXBLOCK_SCALER_CPP__ +/* + * Functions for blitting pixblocks using scaling + * + * Author: + * Niko Kiirala + * + * Copyright (C) 2006 Niko Kiirala + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + #include #include using std::floor; @@ -12,7 +23,20 @@ struct RGBA { int r, g, b, a; }; -inline int sampley(unsigned const char a, unsigned const char b, unsigned const char c, unsigned const char d, const double len) { +/** Calculates cubically interpolated value of the four given pixel values. + * The pixel values should be from four vertically adjacent pixels. + * If we are calculating a pixel, whose y-coordinate in source image is + * i, these pixel values a, b, c and d should come from lines + * floor(i) - 1, floor(i), floor(i) + 1, floor(i) + 2, respectively. + * Parameter len should be set to i. + * Returns the interpolated value in fixed point format with 8 bit + * decimal part. (24.8 assuming 32-bit int) + */ +__attribute__ ((const)) +inline int sampley(unsigned const char a, unsigned const char b, + unsigned const char c, unsigned const char d, + const double len) +{ double lenf = len - floor(len); int sum = 0; sum += (int)((((-1.0 / 3.0) * lenf + 4.0 / 5.0) * lenf - 7.0 / 15.0) @@ -26,6 +50,17 @@ inline int sampley(unsigned const char a, unsigned const char b, unsigned const return sum; } +/** Calculates cubically interpolated value of the four given pixel values. + * The pixel values should be interpolated values from sampley, from four + * horizontally adjacent vertical lines. The parameters a, b, c and d + * should be in fixed point format with 8-bit decimal part. + * If we are calculating a pixel, whose x-coordinate in source image is + * i, these vertical lines from where a, b, c and d are calculated, should be + * floor(i) - 1, floor(i), floor(i) + 1, floor(i) + 2, respectively. + * Parameter len should be set to i. + * Returns the interpolated value in 8-bit format, ready to be written + * to output buffer. + */ inline unsigned char samplex(const int a, const int b, const int c, const int d, const double len) { double lenf = len - floor(len); int sum = 0; @@ -34,7 +69,7 @@ inline unsigned char samplex(const int a, const int b, const int c, const int d, sum += (int)(c * ((((1 - lenf) - 9.0 / 5.0) * (1 - lenf) - 1.0 / 5.0) * (1 - lenf) + 1.0)); sum += (int)(d * (((-1.0 / 3.0) * (1 - lenf) + 4.0 / 5.0) * (1 - lenf) - 7.0 / 15.0) * (1 - lenf)); if (sum < 0) sum = 0; - if (sum > 255*256) sum = 255 * 256; + if (sum >= 256*256) sum = 255 * 256; return (unsigned char)(sum / 256); } @@ -54,16 +89,27 @@ inline void _check_index(NRPixBlock const * const pb, int const location, int co void scale_bicubic(NRPixBlock *to, NRPixBlock *from) { + if (NR_PIXBLOCK_BPP(from) != 4 || NR_PIXBLOCK_BPP(to) != 4) { + g_warning("A non-32-bpp image passed to scale_bicubic: scaling aborted."); + return; + } + + // Precalculate sizes of source and destination pixblocks int from_width = from->area.x1 - from->area.x0; int from_height = from->area.y1 - from->area.y0; int to_width = to->area.x1 - to->area.x0; int to_height = to->area.y1 - to->area.y0; + // from_step: when advancing one pixel in destination image, + // how much we should advance in source image double from_stepx = (double)from_width / (double)to_width; double from_stepy = (double)from_height / (double)to_height; + // Loop through every pixel of destination image, a line at a time for (int to_y = 0 ; to_y < to_height ; to_y++) { double from_y = to_y * from_stepy + from_stepy / 2; + // Pre-calculate beginning of the four horizontal lines, from + // which we should read int from_line[4]; for (int i = 0 ; i < 4 ; i++) { if ((int)floor(from_y) + i - 1 >= 0) { @@ -76,6 +122,9 @@ void scale_bicubic(NRPixBlock *to, NRPixBlock *from) from_line[i] = 0; } } + // Loop through this horizontal line in destination image + // For every pixel, calculate the color of pixel with + // bicubic interpolation and set the pixel value in destination image for (int to_x = 0 ; to_x < to_width ; to_x++) { double from_x = to_x * from_stepx + from_stepx / 2; RGBA line[4]; diff --git a/src/display/pixblock-scaler.h b/src/display/pixblock-scaler.h index 1e30d0a34..907429257 100644 --- a/src/display/pixblock-scaler.h +++ b/src/display/pixblock-scaler.h @@ -1,10 +1,27 @@ #ifndef __NR_PIXBLOCK_SCALER_H__ #define __NR_PIXBLOCK_SCALER_H__ +/* + * Functions for blitting pixblocks using scaling + * + * Author: + * Niko Kiirala + * + * Copyright (C) 2006 Niko Kiirala + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + #include "libnr/nr-pixblock.h" namespace NR { +/** Blits the second pixblock to the first. + * Image in source pixblock is scaled to the size of destination pixblock + * using bicubic interpolation. + * Source pixblock is not modified in process. + * Only works for 32-bpp images. + */ void scale_bicubic(NRPixBlock *to, NRPixBlock *from); } /* namespace NR */ -- 2.30.2