diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2011-06-20 19:33:57 +0000 |
|---|---|---|
| committer | Krzysztof KosiĆski <tweenk.pl@gmail.com> | 2011-06-20 19:33:57 +0000 |
| commit | a39e3c37a508f9a389fc55270ae0336ad2f76f0e (patch) | |
| tree | 952db81c3238005e975f21845734444bba28ff40 /src | |
| parent | Measure Tool: support measuring of text elements (without having to manually ... (diff) | |
| parent | Fix outline view (diff) | |
| download | inkscape-a39e3c37a508f9a389fc55270ae0336ad2f76f0e.tar.gz inkscape-a39e3c37a508f9a389fc55270ae0336ad2f76f0e.zip | |
Merge Cairo rendering branch
(bzr r10326)
Diffstat (limited to 'src')
369 files changed, 6849 insertions, 19602 deletions
diff --git a/src/2geom/Makefile_insert b/src/2geom/Makefile_insert index 174f56433..4f7c3b6ef 100644 --- a/src/2geom/Makefile_insert +++ b/src/2geom/Makefile_insert @@ -6,6 +6,7 @@ rm -f 2geom/lib2geom.a $(2geom_lib2geom_a_OBJECTS) 2geom_lib2geom_a_SOURCES = \ + 2geom/affine.h \ 2geom/affine.cpp \ 2geom/angle.h \ 2geom/basic-intersection.cpp \ @@ -50,7 +51,6 @@ 2geom/linear.h \ 2geom/line.cpp \ 2geom/line.h \ - 2geom/matrix.h \ 2geom/nearest-point.cpp \ 2geom/nearest-point.h \ 2geom/numeric/fitting-model.h \ diff --git a/src/Makefile.am b/src/Makefile.am index 731e9bfd6..40ecc1ec7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -185,8 +185,6 @@ EXTRA_DIST += \ widgets/makefile.in \ xml/makefile.in \ 2geom/makefile.in \ - extension/internal/win32.cpp \ - extension/internal/win32.h \ extension/internal/emf-win32-inout.cpp \ extension/internal/emf-win32-inout.h \ extension/internal/emf-win32-print.cpp \ @@ -270,7 +268,7 @@ TESTS = $(check_PROGRAMS) ../share/extensions/test/run-all-extension-tests XFAIL_TESTS = $(check_PROGRAMS) ../share/extensions/test/run-all-extension-tests # including the the testsuites here ensures that they get distributed -cxxtests_SOURCES = cxxtests.cpp libnr/nr-compose-reference.cpp $(CXXTEST_TESTSUITES) +cxxtests_SOURCES = cxxtests.cpp $(CXXTEST_TESTSUITES) cxxtests_LDADD = $(all_libs) cxxtests.cpp: $(CXXTEST_TESTSUITES) $(CXXTEST_TEMPLATE) diff --git a/src/Makefile_insert b/src/Makefile_insert index aadf9d404..7d48dba93 100644 --- a/src/Makefile_insert +++ b/src/Makefile_insert @@ -153,7 +153,6 @@ ink_common_sources += \ sp-desc.cpp sp-desc.h \ sp-ellipse.cpp sp-ellipse.h \ sp-filter.cpp sp-filter.h number-opt-number.h \ - sp-filter-fns.h \ sp-filter-primitive.cpp sp-filter-primitive.h \ sp-filter-reference.cpp sp-filter-reference.h \ sp-filter-units.h \ @@ -162,8 +161,6 @@ ink_common_sources += \ sp-flowtext.h sp-flowtext.cpp \ sp-font.cpp sp-font.h \ sp-font-face.cpp sp-font-face.h \ - sp-gaussian-blur.cpp sp-gaussian-blur.h \ - sp-gaussian-blur-fns.h \ sp-glyph.cpp sp-glyph.h \ sp-glyph-kerning.cpp sp-glyph-kerning.h \ sp-gradient.cpp sp-gradient.h \ diff --git a/src/box3d.cpp b/src/box3d.cpp index a1ac84f14..ac5814e4d 100644 --- a/src/box3d.cpp +++ b/src/box3d.cpp @@ -386,7 +386,7 @@ Geom::Point box3d_get_corner_screen (SPBox3D const *box, guint id, bool item_coords) { Proj::Pt3 proj_corner (box3d_get_proj_corner (box, id)); if (!box3d_get_perspective(box)) { - return Geom::Point (NR_HUGE, NR_HUGE); + return Geom::Point (Geom::infinity(), Geom::infinity()); } Geom::Affine const i2d (SP_ITEM(box)->i2d_affine ()); if (item_coords) { @@ -410,7 +410,7 @@ Geom::Point box3d_get_center_screen (SPBox3D *box) { Proj::Pt3 proj_center (box3d_get_proj_center (box)); if (!box3d_get_perspective(box)) { - return Geom::Point (NR_HUGE, NR_HUGE); + return Geom::Point (Geom::infinity(), Geom::infinity()); } Geom::Affine const i2d (SP_ITEM(box)->i2d_affine ()); return box3d_get_perspective(box)->perspective_impl->tmat.image(proj_center).affine() * i2d.inverse(); @@ -484,7 +484,7 @@ box3d_snap (SPBox3D *box, int id, Proj::Pt3 const &pt_proj, Proj::Pt3 const &sta // find the closest snapping point int snap_index = -1; - double snap_dist = NR_HUGE; + double snap_dist = Geom::infinity(); for (int i = 0; i < num_snap_lines; ++i) { if (snap_dists[i] < snap_dist) { snap_index = i; diff --git a/src/color-profile-fns.h b/src/color-profile-fns.h index 3d22417f6..defc58f2c 100644 --- a/src/color-profile-fns.h +++ b/src/color-profile-fns.h @@ -38,6 +38,7 @@ std::vector<Glib::ustring> colorprofile_get_display_names(); std::vector<Glib::ustring> colorprofile_get_softproof_names(); Glib::ustring get_path_for_profile(Glib::ustring const& name); +void colorprofile_load_profiles(bool force_refresh = false); #endif diff --git a/src/color-profile.cpp b/src/color-profile.cpp index 9ba49d488..4dc4d5bd8 100644 --- a/src/color-profile.cpp +++ b/src/color-profile.cpp @@ -86,6 +86,9 @@ extern guint update_in_progress; g_message( __VA_ARGS__ );\ } +#else +#define DEBUG_MESSAGE_SCISLAC(key, ...) +#define DEBUG_MESSAGE(key, ...) #endif // DEBUG_LCMS static SPObjectClass *cprof_parent_class; @@ -312,9 +315,7 @@ void ColorProfile::set( SPObject *object, unsigned key, gchar const *value ) cprof->_profileSpace = cmsGetColorSpace( cprof->profHandle ); cprof->_profileClass = cmsGetDeviceClass( cprof->profHandle ); } -#ifdef DEBUG_LCMS DEBUG_MESSAGE( lcmsOne, "cmsOpenProfileFromFile( '%s'...) = %p", fullname, (void*)cprof->profHandle ); -#endif // DEBUG_LCMS g_free(escaped); escaped = 0; g_free(fullname); @@ -339,9 +340,7 @@ void ColorProfile::set( SPObject *object, unsigned key, gchar const *value ) cprof->name = 0; } cprof->name = g_strdup( value ); -#ifdef DEBUG_LCMS DEBUG_MESSAGE( lcmsTwo, "<color-profile> name set to '%s'", cprof->name ); -#endif // DEBUG_LCMS object->requestModified(SP_OBJECT_MODIFIED_FLAG); break; @@ -506,9 +505,7 @@ cmsHPROFILE Inkscape::colorprofile_get_handle( SPDocument* document, guint* inte *intent = thing ? COLORPROFILE(thing)->rendering_intent : (guint)RENDERING_INTENT_UNKNOWN; } -#ifdef DEBUG_LCMS DEBUG_MESSAGE( lcmsThree, "<color-profile> queried for profile of '%s'. Returning %p with intent of %d", name, prof, (intent? *intent:0) ); -#endif // DEBUG_LCMS return prof; } @@ -517,7 +514,7 @@ cmsHTRANSFORM ColorProfile::getTransfToSRGB8() { if ( !_transf && profHandle ) { int intent = getLcmsIntent(rendering_intent); - _transf = cmsCreateTransform( profHandle, _getInputFormat(_profileSpace), getSRGBProfile(), TYPE_RGBA_8, intent, 0 ); + _transf = cmsCreateTransform( profHandle, _getInputFormat(_profileSpace), getSRGBProfile(), TYPE_BGRA_8, intent, 0 ); } return _transf; } @@ -526,7 +523,7 @@ cmsHTRANSFORM ColorProfile::getTransfFromSRGB8() { if ( !_revTransf && profHandle ) { int intent = getLcmsIntent(rendering_intent); - _revTransf = cmsCreateTransform( getSRGBProfile(), TYPE_RGBA_8, profHandle, _getInputFormat(_profileSpace), intent, 0 ); + _revTransf = cmsCreateTransform( getSRGBProfile(), TYPE_BGRA_8, profHandle, _getInputFormat(_profileSpace), intent, 0 ); } return _revTransf; } @@ -534,7 +531,7 @@ cmsHTRANSFORM ColorProfile::getTransfFromSRGB8() cmsHTRANSFORM ColorProfile::getTransfGamutCheck() { if ( !_gamutTransf ) { - _gamutTransf = cmsCreateProofingTransform(getSRGBProfile(), TYPE_RGBA_8, getNULLProfile(), TYPE_GRAY_8, profHandle, INTENT_RELATIVE_COLORIMETRIC, INTENT_RELATIVE_COLORIMETRIC, (cmsFLAGS_GAMUTCHECK|cmsFLAGS_SOFTPROOFING)); + _gamutTransf = cmsCreateProofingTransform(getSRGBProfile(), TYPE_BGRA_8, getNULLProfile(), TYPE_GRAY_8, profHandle, INTENT_RELATIVE_COLORIMETRIC, INTENT_RELATIVE_COLORIMETRIC, (cmsFLAGS_GAMUTCHECK|cmsFLAGS_SOFTPROOFING)); } return _gamutTransf; } @@ -589,6 +586,7 @@ static std::vector<ProfileInfo> knownProfiles; std::vector<Glib::ustring> Inkscape::colorprofile_get_display_names() { + colorprofile_load_profiles(); std::vector<Glib::ustring> result; for ( std::vector<ProfileInfo>::iterator it = knownProfiles.begin(); it != knownProfiles.end(); ++it ) { @@ -602,6 +600,7 @@ std::vector<Glib::ustring> Inkscape::colorprofile_get_display_names() std::vector<Glib::ustring> Inkscape::colorprofile_get_softproof_names() { + colorprofile_load_profiles(); std::vector<Glib::ustring> result; for ( std::vector<ProfileInfo>::iterator it = knownProfiles.begin(); it != knownProfiles.end(); ++it ) { @@ -615,6 +614,7 @@ std::vector<Glib::ustring> Inkscape::colorprofile_get_softproof_names() Glib::ustring Inkscape::get_path_for_profile(Glib::ustring const& name) { + colorprofile_load_profiles(); Glib::ustring result; for ( std::vector<ProfileInfo>::iterator it = knownProfiles.begin(); it != knownProfiles.end(); ++it ) { @@ -775,7 +775,28 @@ std::list<Glib::ustring> ColorProfile::getProfileFiles() } #if ENABLE_LCMS -static void findThings() { + +int errorHandlerCB(int ErrorCode, const char *ErrorText) +{ + g_message("lcms: Error %d; %s", ErrorCode, ErrorText); + + return 1; +} + +/* This function loads or refreshes data in knownProfiles. + * Call it at the start of every call that requires this data. */ +void Inkscape::colorprofile_load_profiles(bool force_refresh) +{ + static bool error_handler_set = false; + if (!error_handler_set) { + cmsSetErrorHandler(errorHandlerCB); + error_handler_set = true; + } + + static bool profiles_searched = false; + if (profiles_searched && !force_refresh) return; + + knownProfiles.clear(); std::list<Glib::ustring> files = ColorProfile::getProfileFiles(); for ( std::list<Glib::ustring>::const_iterator it = files.begin(); it != files.end(); ++it ) { @@ -797,13 +818,7 @@ static void findThings() { } } } -} - -int errorHandlerCB(int ErrorCode, const char *ErrorText) -{ - g_message("lcms: Error %d; %s", ErrorCode, ErrorText); - - return 1; + profiles_searched = true; } static bool gamutWarn = false; @@ -821,13 +836,7 @@ cmsHPROFILE Inkscape::colorprofile_get_system_profile_handle() static cmsHPROFILE theOne = 0; static Glib::ustring lastURI; - static bool init = false; - if ( !init ) { - cmsSetErrorHandler(errorHandlerCB); - - findThings(); - init = true; - } + colorprofile_load_profiles(); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); Glib::ustring uri = prefs->getString("/options/displayprofile/uri"); @@ -880,13 +889,7 @@ cmsHPROFILE Inkscape::colorprofile_get_proof_profile_handle() static cmsHPROFILE theOne = 0; static Glib::ustring lastURI; - static bool init = false; - if ( !init ) { - cmsSetErrorHandler(errorHandlerCB); - - findThings(); - init = true; - } + colorprofile_load_profiles(); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool which = prefs->getBool( "/options/softproof/enable"); @@ -1003,9 +1006,9 @@ cmsHTRANSFORM Inkscape::colorprofile_get_display_transform() dwFlags |= cmsFLAGS_PRESERVEBLACK; } #endif // defined(cmsFLAGS_PRESERVEBLACK) - transf = cmsCreateProofingTransform( ColorProfile::getSRGBProfile(), TYPE_RGBA_8, hprof, TYPE_RGBA_8, proofProf, intent, proofIntent, dwFlags ); + transf = cmsCreateProofingTransform( ColorProfile::getSRGBProfile(), TYPE_BGRA_8, hprof, TYPE_BGRA_8, proofProf, intent, proofIntent, dwFlags ); } else if ( hprof ) { - transf = cmsCreateTransform( ColorProfile::getSRGBProfile(), TYPE_RGBA_8, hprof, TYPE_RGBA_8, intent, 0 ); + transf = cmsCreateTransform( ColorProfile::getSRGBProfile(), TYPE_BGRA_8, hprof, TYPE_BGRA_8, intent, 0 ); } } @@ -1163,9 +1166,9 @@ cmsHTRANSFORM Inkscape::colorprofile_get_display_per( Glib::ustring const& id ) dwFlags |= cmsFLAGS_PRESERVEBLACK; } #endif // defined(cmsFLAGS_PRESERVEBLACK) - item.transf = cmsCreateProofingTransform( ColorProfile::getSRGBProfile(), TYPE_RGBA_8, item.hprof, TYPE_RGBA_8, proofProf, intent, proofIntent, dwFlags ); + item.transf = cmsCreateProofingTransform( ColorProfile::getSRGBProfile(), TYPE_BGRA_8, item.hprof, TYPE_BGRA_8, proofProf, intent, proofIntent, dwFlags ); } else if ( item.hprof ) { - item.transf = cmsCreateTransform( ColorProfile::getSRGBProfile(), TYPE_RGBA_8, item.hprof, TYPE_RGBA_8, intent, 0 ); + item.transf = cmsCreateTransform( ColorProfile::getSRGBProfile(), TYPE_BGRA_8, item.hprof, TYPE_BGRA_8, intent, 0 ); } } diff --git a/src/color-rgba.h b/src/color-rgba.h index fc52b193d..8c21d5e52 100644 --- a/src/color-rgba.h +++ b/src/color-rgba.h @@ -14,7 +14,6 @@ #include <glib.h> // g_assert() #include <glib/gmessages.h> -#include "libnr/nr-pixops.h" #include "decimal-round.h" /** @@ -56,12 +55,12 @@ public: TODO : maybe get rid of the NR_RGBA32_x C-style functions and replace the calls with the bitshifting they do */ - ColorRGBA(unsigned int intcolor) + ColorRGBA(guint32 intcolor) { - _c[0] = NR_RGBA32_R(intcolor)/255.0; - _c[1] = NR_RGBA32_G(intcolor)/255.0; - _c[2] = NR_RGBA32_B(intcolor)/255.0; - _c[3] = NR_RGBA32_A(intcolor)/255.0; + _c[0] = ((intcolor & 0xff000000) >> 24) / 255.0; + _c[1] = ((intcolor & 0x00ff0000) >> 16) / 255.0; + _c[2] = ((intcolor & 0x0000ff00) >> 8) / 255.0; + _c[3] = ((intcolor & 0x000000ff) >> 0) / 255.0; } diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 2c20964aa..88ad9ca57 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -28,7 +28,7 @@ #include "filters/blend.h" #include "sp-filter.h" #include "sp-filter-reference.h" -#include "sp-gaussian-blur.h" +#include "filters/gaussian-blur.h" #include "sp-flowtext.h" #include "sp-flowregion.h" #include "sp-flowdiv.h" @@ -410,7 +410,7 @@ gdouble stroke_average_width (GSList const *objects) { if (g_slist_length ((GSList *) objects) == 0) - return NR_HUGE; + return Geom::infinity(); gdouble avgwidth = 0.0; bool notstroked = true; @@ -435,7 +435,7 @@ stroke_average_width (GSList const *objects) } if (notstroked) - return NR_HUGE; + return Geom::infinity(); return avgwidth / (g_slist_length ((GSList *) objects) - n_notstroked); } diff --git a/src/desktop.cpp b/src/desktop.cpp index cfd3dddd0..f12f83ca6 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -824,7 +824,7 @@ SPDesktop::set_display_area (double x0, double y0, double x1, double y1, double newscale = CLAMP(newscale, SP_DESKTOP_ZOOM_MIN, SP_DESKTOP_ZOOM_MAX); // unit: 'screen pixels' per 'document pixels' int clear = FALSE; - if (!NR_DF_TEST_CLOSE (newscale, scale, 1e-4 * scale)) { + if (!Geom::are_near(newscale, scale, Geom::EPSILON * scale)) { // zoom changed - set new zoom factors _d2w = Geom::Scale(newscale, -newscale); _w2d = Geom::Scale(1/newscale, 1/-newscale); diff --git a/src/dialogs/clonetiler.cpp b/src/dialogs/clonetiler.cpp index 0cfa1d3c9..60ec4f9f7 100644 --- a/src/dialogs/clonetiler.cpp +++ b/src/dialogs/clonetiler.cpp @@ -18,32 +18,33 @@ #include <gtk/gtk.h> #include <glibmm/i18n.h> -#include "../desktop.h" -#include "../desktop-handles.h" +#include "desktop.h" +#include "desktop-handles.h" #include "dialog-events.h" +#include "display/cairo-utils.h" #include "display/nr-arena.h" #include "display/nr-arena-item.h" -#include "../document.h" -#include "../filter-chemistry.h" +#include "document.h" +#include "filter-chemistry.h" #include "helper/unit-menu.h" #include "helper/units.h" #include "helper/window.h" -#include "../inkscape.h" -#include "../interface.h" -#include "../macros.h" -#include "../message-stack.h" +#include "inkscape.h" +#include "interface.h" +#include "macros.h" +#include "message-stack.h" #include "preferences.h" -#include "../selection.h" -#include "../sp-filter.h" -#include "../sp-namedview.h" -#include "../sp-use.h" -#include "../style.h" +#include "selection.h" +#include "sp-filter.h" +#include "sp-namedview.h" +#include "sp-use.h" +#include "style.h" #include "svg/svg-color.h" #include "svg/svg.h" #include "ui/icon-names.h" #include "ui/widget/color-picker.h" #include "unclump.h" -#include "../verbs.h" +#include "verbs.h" #include "widgets/icon.h" #include "xml/repr.h" #include "sp-root.h" @@ -879,60 +880,25 @@ static guint32 clonetiler_trace_pick(Geom::Rect box) /* Item integer bbox in points */ NRRectL ibox; - ibox.x0 = (int) floor(trace_zoom * box[Geom::X].min() + 0.5); - ibox.y0 = (int) floor(trace_zoom * box[Geom::Y].min() + 0.5); - ibox.x1 = (int) floor(trace_zoom * box[Geom::X].max() + 0.5); - ibox.y1 = (int) floor(trace_zoom * box[Geom::Y].max() + 0.5); + ibox.x0 = floor(trace_zoom * box[Geom::X].min()); + ibox.y0 = floor(trace_zoom * box[Geom::Y].min()); + ibox.x1 = ceil(trace_zoom * box[Geom::X].max()); + ibox.y1 = ceil(trace_zoom * box[Geom::Y].max()); /* Find visible area */ int width = ibox.x1 - ibox.x0; int height = ibox.y1 - ibox.y0; + double R = 0, G = 0, B = 0, A = 0; - /* Set up pixblock */ - guchar *px = g_new(guchar, 4 * width * height); - - if (px == NULL) { - return 0; // buffer is too big or too small, cannot pick, so return 0 - } - - memset(px, 0x00, 4 * width * height); - + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + cairo_t *ct = cairo_create(s); + cairo_translate(ct, -ibox.x0, -ibox.y0); /* Render */ - NRPixBlock pb; - nr_pixblock_setup_extern( &pb, NR_PIXBLOCK_MODE_R8G8B8A8N, - ibox.x0, ibox.y0, ibox.x1, ibox.y1, - px, 4 * width, FALSE, FALSE ); - nr_arena_item_invoke_render(NULL, trace_root, &ibox, &pb, + nr_arena_item_invoke_render(ct, trace_root, &ibox, NULL, NR_ARENA_ITEM_RENDER_NO_CACHE ); - - double R = 0, G = 0, B = 0, A = 0; - double count = 0; - double weight = 0; - - for (int y = ibox.y0; y < ibox.y1; y++) { - const unsigned char *s = NR_PIXBLOCK_PX (&pb) + (y - ibox.y0) * pb.rs; - for (int x = ibox.x0; x < ibox.x1; x++) { - count += 1; - weight += s[3] / 255.0; - R += s[0] / 255.0; - G += s[1] / 255.0; - B += s[2] / 255.0; - A += s[3] / 255.0; - s += 4; - } - } - - nr_pixblock_release(&pb); - - R = R / weight; - G = G / weight; - B = B / weight; - A = A / count; - - R = CLAMP (R, 0.0, 1.0); - G = CLAMP (G, 0.0, 1.0); - B = CLAMP (B, 0.0, 1.0); - A = CLAMP (A, 0.0, 1.0); + cairo_destroy(ct); + ink_cairo_surface_average_color(s, R, G, B, A); + cairo_surface_destroy(s); return SP_RGBA32_F_COMPOSE (R, G, B, A); } diff --git a/src/dialogs/text-edit.cpp b/src/dialogs/text-edit.cpp index 2e49cae8f..81bd0f5d2 100644 --- a/src/dialogs/text-edit.cpp +++ b/src/dialogs/text-edit.cpp @@ -369,8 +369,11 @@ sp_text_edit_dialog (void) } /* Font preview */ - GtkWidget *preview = sp_font_preview_new (); - gtk_box_pack_start (GTK_BOX (vb), preview, TRUE, TRUE, 4); + GtkLabel *preview = (GtkLabel*) gtk_label_new(NULL); + gtk_label_set_ellipsize(preview, PANGO_ELLIPSIZE_END); + gtk_label_set_justify(preview, GTK_JUSTIFY_CENTER); + gtk_label_set_line_wrap(preview, FALSE); + gtk_box_pack_start (GTK_BOX (vb), (GtkWidget*) preview, TRUE, TRUE, 4); g_object_set_data (G_OBJECT (dlg), "preview", preview); } @@ -697,7 +700,7 @@ sp_text_edit_dialog_read_selection ( GtkWidget *dlg, g_object_set_data (G_OBJECT (dlg), "blocked", GINT_TO_POINTER (TRUE)); - GtkWidget *notebook = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "notebook"); + //GtkWidget *notebook = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "notebook"); GtkWidget *textw = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "textw"); GtkWidget *fontsel = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "fontsel"); GtkWidget *preview = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "preview"); @@ -708,6 +711,12 @@ sp_text_edit_dialog_read_selection ( GtkWidget *dlg, SPItem *text = sp_ted_get_selected_text_item (); + /* TRANSLATORS: Test string used in text and font dialog (when no + * text has been entered) to get a preview of the font. Choose + * some representative characters that users of your locale will be + * interested in. */ + gchar *phrase = g_strdup(_("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()")); + Inkscape::XML::Node *repr; if (text) { @@ -732,12 +741,10 @@ sp_text_edit_dialog_read_selection ( GtkWidget *dlg, gtk_text_buffer_set_text (tb, str, strlen (str)); gtk_text_buffer_set_modified (tb, FALSE); } - sp_font_preview_set_phrase (SP_FONT_PREVIEW (preview), str); - g_free (str); + phrase = str; } else { gtk_text_buffer_set_text (tb, "", 0); - sp_font_preview_set_phrase (SP_FONT_PREVIEW (preview), NULL); } } // end of if (docontent) repr = text->getRepr(); @@ -774,7 +781,13 @@ sp_text_edit_dialog_read_selection ( GtkWidget *dlg, if (font) { // the font is oversized, so we need to pass the true size separately sp_font_selector_set_font (SP_FONT_SELECTOR (fontsel), font, query->font_size.computed); - sp_font_preview_set_font (SP_FONT_PREVIEW (preview), font, SP_FONT_SELECTOR(fontsel)); + char *desc = pango_font_description_to_string(font->descr); + double size = sp_font_selector_get_size(SP_FONT_SELECTOR(fontsel)); + gchar *markup = g_strdup_printf("<span font=\"%s\" size=\"%d\">%s</span>", + desc, (int) size * PANGO_SCALE, phrase); + gtk_label_set_markup(GTK_LABEL(preview), markup); + g_free(desc); + g_free(markup); font->Unref(); font=NULL; } @@ -812,7 +825,7 @@ sp_text_edit_dialog_read_selection ( GtkWidget *dlg, sp_style_unref(query); } - + g_free(phrase); g_object_set_data (G_OBJECT (dlg), "blocked", NULL); } @@ -820,7 +833,7 @@ sp_text_edit_dialog_read_selection ( GtkWidget *dlg, static void sp_text_edit_dialog_text_changed (GtkTextBuffer *tb, GtkWidget *dlg) { - GtkWidget *textw, *preview, *apply, *def; + GtkWidget *textw, *preview, *apply, *def, *fontsel; GtkTextIter start, end; gchar *str; @@ -833,14 +846,23 @@ sp_text_edit_dialog_text_changed (GtkTextBuffer *tb, GtkWidget *dlg) preview = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "preview"); apply = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "apply"); def = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "default"); + fontsel = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "fontsel"); gtk_text_buffer_get_bounds (tb, &start, &end); str = gtk_text_buffer_get_text (tb, &start, &end, TRUE); - - if (str && *str) { - sp_font_preview_set_phrase (SP_FONT_PREVIEW (preview), str); + font_instance *font = sp_font_selector_get_font(SP_FONT_SELECTOR(fontsel)); + + if (font) { + gchar *phrase = str && *str ? str : _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()"); + char *desc = pango_font_description_to_string(font->descr); + double size = sp_font_selector_get_size(SP_FONT_SELECTOR(fontsel)); + gchar *markup = g_strdup_printf("<span font=\"%s\" size=\"%d\">%s</span>", + desc, (int) size * PANGO_SCALE, phrase); + gtk_label_set_markup(GTK_LABEL(preview), markup); + g_free(desc); + g_free(markup); } else { - sp_font_preview_set_phrase (SP_FONT_PREVIEW (preview), NULL); + gtk_label_set_markup(GTK_LABEL(preview), NULL); } g_free (str); @@ -865,7 +887,9 @@ sp_text_edit_dialog_font_changed ( SPFontSelector *fsel, font_instance *font, GtkWidget *dlg ) { - GtkWidget *preview, *apply, *def; + GtkWidget *preview, *apply, *def, *fontsel; + GtkTextIter start, end; + gchar *str; if (g_object_get_data (G_OBJECT (dlg), "blocked")) return; @@ -875,11 +899,27 @@ sp_text_edit_dialog_font_changed ( SPFontSelector *fsel, preview = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "preview"); apply = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "apply"); def = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "default"); + fontsel = (GtkWidget*)g_object_get_data (G_OBJECT (dlg), "fontsel"); + + GtkTextBuffer *tb = (GtkTextBuffer*)g_object_get_data (G_OBJECT (dlg), "text"); + gtk_text_buffer_get_bounds (tb, &start, &end); + str = gtk_text_buffer_get_text (tb, &start, &end, TRUE); - sp_font_preview_set_font (SP_FONT_PREVIEW (preview), font, SP_FONT_SELECTOR(fsel)); + if (font) { + gchar *phrase = str && *str ? str : _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()"); + char *desc = pango_font_description_to_string(font->descr); + double size = sp_font_selector_get_size(SP_FONT_SELECTOR(fontsel)); + gchar *markup = g_strdup_printf("<span font=\"%s\" size=\"%d\">%s</span>", + desc, (int) size * PANGO_SCALE, phrase); + gtk_label_set_markup(GTK_LABEL(preview), markup); + g_free(desc); + g_free(markup); + } else { + gtk_label_set_markup(GTK_LABEL(preview), NULL); + } + g_free(str); - if (text) - { + if (text) { gtk_widget_set_sensitive (apply, TRUE); } gtk_widget_set_sensitive (def, TRUE); diff --git a/src/display/Makefile_insert b/src/display/Makefile_insert index 370e28d6d..fc7c8e9ab 100644 --- a/src/display/Makefile_insert +++ b/src/display/Makefile_insert @@ -4,35 +4,23 @@ display/canvas-arena.$(OBJEXT): helper/sp-marshal.h display/sp-canvas.$(OBJEXT): helper/sp-marshal.h ink_common_sources += \ - display/nr-3dutils.h \ - display/nr-3dutils.cpp \ - display/nr-arena-forward.h \ - display/nr-arena.cpp \ - display/nr-arena.h \ - display/nr-arena-item.cpp \ - display/nr-arena-item.h \ - display/nr-arena-group.cpp \ - display/nr-arena-group.h \ - display/nr-arena-image.cpp \ - display/nr-arena-image.h \ - display/nr-arena-shape.cpp \ - display/nr-arena-shape.h \ - display/nr-arena-glyphs.cpp \ - display/nr-arena-glyphs.h \ + display/cairo-templates.h \ + display/cairo-utils.cpp \ + display/cairo-utils.h \ display/canvas-arena.cpp \ display/canvas-arena.h \ + display/canvas-axonomgrid.cpp \ + display/canvas-axonomgrid.h \ display/canvas-bpath.cpp \ display/canvas-bpath.h \ display/canvas-grid.cpp \ display/canvas-grid.h \ - display/canvas-axonomgrid.cpp \ - display/canvas-axonomgrid.h \ display/canvas-temporary-item.cpp \ display/canvas-temporary-item.h \ display/canvas-temporary-item-list.cpp \ display/canvas-temporary-item-list.h \ - display/canvas-text.h \ display/canvas-text.cpp \ + display/canvas-text.h \ display/curve.cpp \ display/curve.h \ display/gnome-canvas-acetate.cpp \ @@ -41,43 +29,32 @@ ink_common_sources += \ display/grayscale.h \ display/guideline.cpp \ display/guideline.h \ - display/nr-plain-stuff-gdk.cpp \ - display/nr-plain-stuff-gdk.h \ - display/nr-plain-stuff.cpp \ - display/nr-plain-stuff.h \ - display/nr-svgfonts.cpp \ - display/nr-svgfonts.h \ - display/rendermode.h \ - display/snap-indicator.cpp \ - display/snap-indicator.h \ - display/sodipodi-ctrl.cpp \ - display/sodipodi-ctrl.h \ - display/sodipodi-ctrlrect.cpp \ - display/sodipodi-ctrlrect.h \ - display/sp-canvas-group.h \ - display/sp-canvas-item.h \ - display/sp-canvas-util.cpp \ - display/sp-canvas-util.h \ - display/sp-canvas.cpp \ - display/sp-canvas.h \ - display/sp-ctrlline.cpp \ - display/sp-ctrlline.h \ - display/sp-ctrlpoint.cpp \ - display/sp-ctrlpoint.h \ - display/sp-ctrlquadr.cpp \ - display/sp-ctrlquadr.h \ - display/nr-filter.cpp \ - display/nr-filter.h \ + display/nr-3dutils.cpp \ + display/nr-3dutils.h \ + display/nr-arena.cpp \ + display/nr-arena-forward.h \ + display/nr-arena-glyphs.cpp \ + display/nr-arena-glyphs.h \ + display/nr-arena-group.cpp \ + display/nr-arena-group.h \ + display/nr-arena.h \ + display/nr-arena-image.cpp \ + display/nr-arena-image.h \ + display/nr-arena-item.cpp \ + display/nr-arena-item.h \ + display/nr-arena-shape.cpp \ + display/nr-arena-shape.h \ display/nr-filter-blend.cpp \ display/nr-filter-blend.h \ display/nr-filter-colormatrix.cpp \ display/nr-filter-colormatrix.h \ display/nr-filter-component-transfer.cpp \ display/nr-filter-component-transfer.h \ - display/nr-filter-composite.h \ display/nr-filter-composite.cpp \ + display/nr-filter-composite.h \ display/nr-filter-convolve-matrix.cpp \ display/nr-filter-convolve-matrix.h \ + display/nr-filter.cpp \ display/nr-filter-diffuselighting.cpp \ display/nr-filter-diffuselighting.h \ display/nr-filter-displacement-map.cpp \ @@ -86,8 +63,7 @@ ink_common_sources += \ display/nr-filter-flood.h \ display/nr-filter-gaussian.cpp \ display/nr-filter-gaussian.h \ - display/nr-filter-getalpha.cpp \ - display/nr-filter-getalpha.h \ + display/nr-filter.h \ display/nr-filter-image.cpp \ display/nr-filter-image.h \ display/nr-filter-merge.cpp \ @@ -106,21 +82,35 @@ ink_common_sources += \ display/nr-filter-tile.h \ display/nr-filter-turbulence.cpp \ display/nr-filter-turbulence.h \ - display/nr-filter-pixops.h \ display/nr-filter-types.h \ - display/nr-filter-units.h \ display/nr-filter-units.cpp \ - display/nr-filter-utils.h \ + display/nr-filter-units.h \ display/nr-filter-utils.cpp \ - display/pixblock-scaler.cpp \ - display/pixblock-scaler.h \ - display/pixblock-transform.cpp \ - display/pixblock-transform.h \ - display/inkscape-cairo.cpp \ - display/inkscape-cairo.h \ - display/nr-light.h \ + display/nr-filter-utils.h \ display/nr-light.cpp \ - display/nr-light-types.h + display/nr-light.h \ + display/nr-light-types.h \ + display/nr-style.cpp \ + display/nr-style.h \ + display/nr-svgfonts.cpp \ + display/nr-svgfonts.h \ + display/rendermode.h \ + display/snap-indicator.cpp \ + display/snap-indicator.h \ + display/sodipodi-ctrl.cpp \ + display/sodipodi-ctrl.h \ + display/sodipodi-ctrlrect.cpp \ + display/sodipodi-ctrlrect.h \ + display/sp-canvas.cpp \ + display/sp-canvas.h \ + display/sp-canvas-util.cpp \ + display/sp-canvas-util.h \ + display/sp-ctrlline.cpp \ + display/sp-ctrlline.h \ + display/sp-ctrlpoint.cpp \ + display/sp-ctrlpoint.h \ + display/sp-ctrlquadr.cpp \ + display/sp-ctrlquadr.h # ###################### # ### CxxTest stuff #### diff --git a/src/display/cairo-templates.h b/src/display/cairo-templates.h new file mode 100644 index 000000000..a79f58548 --- /dev/null +++ b/src/display/cairo-templates.h @@ -0,0 +1,689 @@ +/** + * @file + * @brief Cairo software blending templates + *//* + * Authors: + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * + * Copyright (C) 2010 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_CAIRO_TEMPLATES_H +#define SEEN_INKSCAPE_DISPLAY_CAIRO_TEMPLATES_H + +#ifdef HAVE_OPENMP +#include <omp.h> +#include "preferences.h" +// single-threaded operation if the number of pixels is below this threshold +static const int OPENMP_THRESHOLD = 2048; +#endif + +#include <algorithm> +#include <cairo.h> +#include <glib.h> +#include <math.h> +#include "display/nr-3dutils.h" +#include "display/cairo-utils.h" + +/** + * @brief Blend two surfaces using the supplied functor. + * This template blends two Cairo image surfaces using a blending functor that takes + * two 32-bit ARGB pixel values and returns a modified 32-bit pixel value. + * Differences in input surface formats are handled transparently. In future, this template + * will also handle software fallback for GL surfaces. */ +template <typename Blend> +void ink_cairo_surface_blend(cairo_surface_t *in1, cairo_surface_t *in2, cairo_surface_t *out, Blend blend) +{ + cairo_surface_flush(in1); + cairo_surface_flush(in2); + + // ASSUMPTIONS + // 1. Cairo ARGB32 surface strides are always divisible by 4 + // 2. We can only receive CAIRO_FORMAT_ARGB32 or CAIRO_FORMAT_A8 surfaces + // 3. Both surfaces are of the same size + // 4. Output surface is ARGB32 if at least one input is ARGB32 + + int w = cairo_image_surface_get_width(in2); + int h = cairo_image_surface_get_height(in2); + int stride1 = cairo_image_surface_get_stride(in1); + int stride2 = cairo_image_surface_get_stride(in2); + int strideout = cairo_image_surface_get_stride(out); + int bpp1 = cairo_image_surface_get_format(in1) == CAIRO_FORMAT_A8 ? 1 : 4; + int bpp2 = cairo_image_surface_get_format(in2) == CAIRO_FORMAT_A8 ? 1 : 4; + int bppout = std::max(bpp1, bpp2); + + // Check whether we can loop over pixels without taking stride into account. + bool fast_path = true; + fast_path &= (stride1 == w * bpp1); + fast_path &= (stride2 == w * bpp2); + fast_path &= (strideout == w * bppout); + + int limit = w * h; + + guint32 *const in1_data = (guint32*) cairo_image_surface_get_data(in1); + guint32 *const in2_data = (guint32*) cairo_image_surface_get_data(in2); + guint32 *const out_data = (guint32*) cairo_image_surface_get_data(out); + + // NOTE + // OpenMP probably doesn't help much here. + // It would be better to render more than 1 tile at a time. + #if HAVE_OPENMP + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int num_threads = prefs->getIntLimited("/options/threading/numthreads", omp_get_num_procs(), 1, 256); + #endif + + // The number of code paths here is evil. + if (bpp1 == 4) { + if (bpp2 == 4) { + if (fast_path) { + #if HAVE_OPENMP + #pragma omp parallel for if(limit > OPENMP_THRESHOLD) num_threads(num_threads) + #endif + for (int i = 0; i < limit; ++i) { + *(out_data + i) = blend(*(in1_data + i), *(in2_data + i)); + } + } else { + #if HAVE_OPENMP + #pragma omp parallel for if(limit > OPENMP_THRESHOLD) num_threads(num_threads) + #endif + for (int i = 0; i < h; ++i) { + guint32 *in1_p = in1_data + i * stride1/4; + guint32 *in2_p = in2_data + i * stride2/4; + guint32 *out_p = out_data + i * strideout/4; + for (int j = 0; j < w; ++j) { + *out_p = blend(*in1_p, *in2_p); + ++in1_p; ++in2_p; ++out_p; + } + } + } + } else { + // bpp2 == 1 + #if HAVE_OPENMP + #pragma omp parallel for if(limit > OPENMP_THRESHOLD) num_threads(num_threads) + #endif + for (int i = 0; i < h; ++i) { + guint32 *in1_p = in1_data + i * stride1/4; + guint8 *in2_p = reinterpret_cast<guint8*>(in2_data) + i * stride2; + guint32 *out_p = out_data + i * strideout/4; + for (int j = 0; j < w; ++j) { + guint32 in2_px = *in2_p; + in2_px <<= 24; + *out_p = blend(*in1_p, in2_px); + ++in1_p; ++in2_p; ++out_p; + } + } + } + } else { + if (bpp2 == 4) { + // bpp1 == 1 + #if HAVE_OPENMP + #pragma omp parallel for if(limit > OPENMP_THRESHOLD) num_threads(num_threads) + #endif + for (int i = 0; i < h; ++i) { + guint8 *in1_p = reinterpret_cast<guint8*>(in1_data) + i * stride1; + guint32 *in2_p = in2_data + i * stride2/4; + guint32 *out_p = out_data + i * strideout/4; + for (int j = 0; j < w; ++j) { + guint32 in1_px = *in1_p; + in1_px <<= 24; + *out_p = blend(in1_px, *in2_p); + ++in1_p; ++in2_p; ++out_p; + } + } + } else { + // bpp1 == 1 && bpp2 == 1 + if (fast_path) { + #if HAVE_OPENMP + #pragma omp parallel for if(limit > OPENMP_THRESHOLD) num_threads(num_threads) + #endif + for (int i = 0; i < limit; ++i) { + guint8 *in1_p = reinterpret_cast<guint8*>(in1_data) + i; + guint8 *in2_p = reinterpret_cast<guint8*>(in2_data) + i; + guint8 *out_p = reinterpret_cast<guint8*>(out_data) + i; + guint32 in1_px = *in1_p; in1_px <<= 24; + guint32 in2_px = *in2_p; in2_px <<= 24; + guint32 out_px = blend(in1_px, in2_px); + *out_p = out_px >> 24; + } + } else { + #if HAVE_OPENMP + #pragma omp parallel for if(limit > OPENMP_THRESHOLD) num_threads(num_threads) + #endif + for (int i = 0; i < h; ++i) { + guint8 *in1_p = reinterpret_cast<guint8*>(in1_data) + i * stride1; + guint8 *in2_p = reinterpret_cast<guint8*>(in2_data) + i * stride2; + guint8 *out_p = reinterpret_cast<guint8*>(out_data) + i * strideout; + for (int j = 0; j < w; ++j) { + guint32 in1_px = *in1_p; in1_px <<= 24; + guint32 in2_px = *in2_p; in2_px <<= 24; + guint32 out_px = blend(in1_px, in2_px); + *out_p = out_px >> 24; + ++in1_p; ++in2_p; ++out_p; + } + } + } + } + } + + cairo_surface_mark_dirty(out); +} + +template <typename Filter> +void ink_cairo_surface_filter(cairo_surface_t *in, cairo_surface_t *out, Filter filter) +{ + cairo_surface_flush(in); + + // ASSUMPTIONS + // 1. Cairo ARGB32 surface strides are always divisible by 4 + // 2. We can only receive CAIRO_FORMAT_ARGB32 or CAIRO_FORMAT_A8 surfaces + // 3. Surfaces have the same dimensions + // 4. Output surface is A8 if input is A8 + + int w = cairo_image_surface_get_width(in); + int h = cairo_image_surface_get_height(in); + int stridein = cairo_image_surface_get_stride(in); + int strideout = cairo_image_surface_get_stride(out); + int bppin = cairo_image_surface_get_format(in) == CAIRO_FORMAT_A8 ? 1 : 4; + int bppout = cairo_image_surface_get_format(out) == CAIRO_FORMAT_A8 ? 1 : 4; + int limit = w * h; + + // Check whether we can loop over pixels without taking stride into account. + bool fast_path = true; + fast_path &= (stridein == w * bppin); + fast_path &= (strideout == w * bppout); + + guint32 *const in_data = (guint32*) cairo_image_surface_get_data(in); + guint32 *const out_data = (guint32*) cairo_image_surface_get_data(out); + + #if HAVE_OPENMP + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int num_threads = prefs->getIntLimited("/options/threading/numthreads", omp_get_num_procs(), 1, 256); + #endif + + // this is provided just in case, to avoid problems with strict aliasing rules + if (in == out) { + if (bppin == 4) { + #if HAVE_OPENMP + #pragma omp parallel for if(limit > OPENMP_THRESHOLD) num_threads(num_threads) + #endif + for (int i = 0; i < limit; ++i) { + *(in_data + i) = filter(*(in_data + i)); + } + } else { + #if HAVE_OPENMP + #pragma omp parallel for if(limit > OPENMP_THRESHOLD) num_threads(num_threads) + #endif + for (int i = 0; i < limit; ++i) { + guint8 *in_p = reinterpret_cast<guint8*>(in_data) + i; + guint32 in_px = *in_p; in_px <<= 24; + guint32 out_px = filter(in_px); + *in_p = out_px >> 24; + } + } + cairo_surface_mark_dirty(out); + return; + } + + if (bppin == 4) { + if (bppout == 4) { + // bppin == 4, bppout == 4 + if (fast_path) { + #if HAVE_OPENMP + #pragma omp parallel for if(limit > OPENMP_THRESHOLD) num_threads(num_threads) + #endif + for (int i = 0; i < limit; ++i) { + *(out_data + i) = filter(*(in_data + i)); + } + } else { + #if HAVE_OPENMP + #pragma omp parallel for if(limit > OPENMP_THRESHOLD) num_threads(num_threads) + #endif + for (int i = 0; i < h; ++i) { + guint32 *in_p = in_data + i * stridein/4; + guint32 *out_p = out_data + i * strideout/4; + for (int j = 0; j < w; ++j) { + *out_p = filter(*in_p); + ++in_p; ++out_p; + } + } + } + } else { + // bppin == 4, bppout == 1 + // we use this path with COLORMATRIX_LUMINANCETOALPHA + #if HAVE_OPENMP + #pragma omp parallel for if(limit > OPENMP_THRESHOLD) num_threads(num_threads) + #endif + for (int i = 0; i < h; ++i) { + guint32 *in_p = in_data + i * stridein/4; + guint8 *out_p = reinterpret_cast<guint8*>(out_data) + i * strideout; + for (int j = 0; j < w; ++j) { + guint32 out_px = filter(*in_p); + *out_p = out_px >> 24; + ++in_p; ++out_p; + } + } + } + } else { + // bppin == 1, bppout == 1 + // Note: there is no path for bppin == 1, bppout == 4 because it is useless + if (fast_path) { + #if HAVE_OPENMP + #pragma omp parallel for if(limit > OPENMP_THRESHOLD) num_threads(num_threads) + #endif + for (int i = 0; i < limit; ++i) { + guint8 *in_p = reinterpret_cast<guint8*>(in_data) + i; + guint8 *out_p = reinterpret_cast<guint8*>(out_data) + i; + guint32 in_px = *in_p; in_px <<= 24; + guint32 out_px = filter(in_px); + *out_p = out_px >> 24; + } + } else { + #if HAVE_OPENMP + #pragma omp parallel for if(limit > OPENMP_THRESHOLD) num_threads(num_threads) + #endif + for (int i = 0; i < h; ++i) { + guint8 *in_p = reinterpret_cast<guint8*>(in_data) + i * stridein; + guint8 *out_p = reinterpret_cast<guint8*>(out_data) + i * strideout; + for (int j = 0; j < w; ++j) { + guint32 in_px = *in_p; in_px <<= 24; + guint32 out_px = filter(in_px); + *out_p = out_px >> 24; + ++in_p; ++out_p; + } + } + } + } + cairo_surface_mark_dirty(out); +} + + +/** + * @brief Synthesize surface pixels based on their position. + * This template accepts a functor that gets called with the x and y coordinates of the pixels, + * given as integers. + * @param out Output surface + * @param out_area The region of the output surface that should be synthesized + * @param synth Synthesis functor */ +template <typename Synth> +void ink_cairo_surface_synthesize(cairo_surface_t *out, cairo_rectangle_t const &out_area, Synth synth) +{ + // ASSUMPTIONS + // 1. Cairo ARGB32 surface strides are always divisible by 4 + // 2. We can only receive CAIRO_FORMAT_ARGB32 or CAIRO_FORMAT_A8 surfaces + + int w = out_area.width; + int h = out_area.height; + int strideout = cairo_image_surface_get_stride(out); + int bppout = cairo_image_surface_get_format(out) == CAIRO_FORMAT_A8 ? 1 : 4; + // NOTE: fast path is not used, because we would need 2 divisions to get pixel indices + + unsigned char *out_data = cairo_image_surface_get_data(out); + + #if HAVE_OPENMP + int limit = w * h; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int num_threads = prefs->getIntLimited("/options/threading/numthreads", omp_get_num_procs(), 1, 256); + #endif + + if (bppout == 4) { + #if HAVE_OPENMP + #pragma omp parallel for if(limit > OPENMP_THRESHOLD) num_threads(num_threads) + #endif + for (int i = out_area.y; i < h; ++i) { + guint32 *out_p = reinterpret_cast<guint32*>(out_data + i * strideout); + for (int j = out_area.x; j < w; ++j) { + *out_p = synth(j, i); + ++out_p; + } + } + } else { + // bppout == 1 + #if HAVE_OPENMP + #pragma omp parallel for if(limit > OPENMP_THRESHOLD) num_threads(num_threads) + #endif + for (int i = out_area.y; i < h; ++i) { + guint8 *out_p = out_data + i * strideout; + for (int j = out_area.x; j < w; ++j) { + guint32 out_px = synth(j, i); + *out_p = out_px >> 24; + ++out_p; + } + } + } + cairo_surface_mark_dirty(out); +} + +template <typename Synth> +void ink_cairo_surface_synthesize(cairo_surface_t *out, Synth synth) +{ + int w = cairo_image_surface_get_width(out); + int h = cairo_image_surface_get_height(out); + + cairo_rectangle_t area; + area.x = 0; + area.y = 0; + area.width = w; + area.height = h; + + ink_cairo_surface_synthesize(out, area, synth); +} + +struct SurfaceSynth { + SurfaceSynth(cairo_surface_t *surface) + : _px(cairo_image_surface_get_data(surface)) + , _w(cairo_image_surface_get_width(surface)) + , _h(cairo_image_surface_get_height(surface)) + , _stride(cairo_image_surface_get_stride(surface)) + , _alpha(cairo_surface_get_content(surface) == CAIRO_CONTENT_ALPHA) + { + cairo_surface_flush(surface); + } + + guint32 pixelAt(int x, int y) const { + if (_alpha) { + unsigned char *px = _px + y*_stride + x; + return *px << 24; + } else { + unsigned char *px = _px + y*_stride + x*4; + return *reinterpret_cast<guint32*>(px); + } + } + guint32 alphaAt(int x, int y) const { + if (_alpha) { + unsigned char *px = _px + y*_stride + x; + return *px; + } else { + unsigned char *px = _px + y*_stride + x*4; + guint32 p = *reinterpret_cast<guint32*>(px); + return (p & 0xff000000) >> 24; + } + } + + // retrieve a pixel value with bilinear interpolation + guint32 pixelAt(double x, double y) const { + if (_alpha) { + return alphaAt(x, y) << 24; + } + + double xf = floor(x), yf = floor(y); + int xi = xf, yi = yf; + guint32 xif = round((x - xf) * 255), yif = round((y - yf) * 255); + guint32 p00, p01, p10, p11; + + unsigned char *pxi = _px + yi*_stride + xi*4; + guint32 *pxu = reinterpret_cast<guint32*>(pxi); + guint32 *pxl = reinterpret_cast<guint32*>(pxi + _stride); + p00 = *pxu; p10 = *(pxu + 1); + p01 = *pxl; p11 = *(pxl + 1); + + guint32 comp[4]; + + for (unsigned i = 0; i < 4; ++i) { + guint32 shift = i*8; + guint32 mask = 0xff << shift; + guint32 c00 = (p00 & mask) >> shift; + guint32 c10 = (p10 & mask) >> shift; + guint32 c01 = (p01 & mask) >> shift; + guint32 c11 = (p11 & mask) >> shift; + + guint32 iu = (255-xif) * c00 + xif * c10; + guint32 il = (255-xif) * c01 + xif * c11; + comp[i] = (255-yif) * iu + yif * il; + comp[i] = (comp[i] + (255*255/2)) / (255*255); + } + + guint32 result = comp[0] | (comp[1] << 8) | (comp[2] << 16) | (comp[3] << 24); + return result; + } + + // retrieve an alpha value with bilinear interpolation + guint32 alphaAt(double x, double y) const { + double xf = floor(x), yf = floor(y); + int xi = xf, yi = yf; + guint32 xif = round((x - xf) * 255), yif = round((y - yf) * 255); + guint32 p00, p01, p10, p11; + if (_alpha) { + unsigned char *pxu = _px + yi*_stride + xi; + unsigned char *pxl = pxu + _stride; + p00 = *pxu; p10 = *(pxu + 1); + p01 = *pxl; p11 = *(pxl + 1); + } else { + unsigned char *pxi = _px + yi*_stride + xi*4; + guint32 *pxu = reinterpret_cast<guint32*>(pxi); + guint32 *pxl = reinterpret_cast<guint32*>(pxi + _stride); + p00 = (*pxu & 0xff000000) >> 24; p10 = (*(pxu + 1) & 0xff000000) >> 24; + p01 = (*pxl & 0xff000000) >> 24; p11 = (*(pxl + 1) & 0xff000000) >> 24; + } + guint32 iu = (255-xif) * p00 + xif * p10; + guint32 il = (255-xif) * p01 + xif * p11; + guint32 result = (255-yif) * iu + yif * il; + result = (result + (255*255/2)) / (255*255); + return result; + } + + // compute surface normal at given coordinates using 3x3 Sobel gradient filter + NR::Fvector surfaceNormalAt(int x, int y, double scale) const { + // Below there are some multiplies by zero. They will be optimized out. + // Do not remove them, because they improve readability. + // NOTE: fetching using alphaAt is slightly lazy. + NR::Fvector normal; + double fx = -scale/255.0, fy = -scale/255.0; + normal[Z_3D] = 1.0; + if (G_UNLIKELY(x == 0)) { + // leftmost column + if (G_UNLIKELY(y == 0)) { + // upper left corner + fx *= (2.0/3.0); + fy *= (2.0/3.0); + double p00 = alphaAt(x,y), p10 = alphaAt(x+1, y), + p01 = alphaAt(x,y+1), p11 = alphaAt(x+1, y+1); + normal[X_3D] = + -2.0 * p00 +2.0 * p10 + -1.0 * p01 +1.0 * p11; + normal[Y_3D] = + -2.0 * p00 -1.0 * p10 + +2.0 * p01 +1.0 * p11; + } else if (G_UNLIKELY(y == (_h - 1))) { + // lower left corner + fx *= (2.0/3.0); + fy *= (2.0/3.0); + double p00 = alphaAt(x,y-1), p10 = alphaAt(x+1, y-1), + p01 = alphaAt(x,y ), p11 = alphaAt(x+1, y); + normal[X_3D] = + -1.0 * p00 +1.0 * p10 + -2.0 * p01 +2.0 * p11; + normal[Y_3D] = + -2.0 * p00 -1.0 * p10 + +2.0 * p01 +1.0 * p11; + } else { + // leftmost column + fx *= (1.0/2.0); + fy *= (1.0/3.0); + double p00 = alphaAt(x, y-1), p10 = alphaAt(x+1, y-1), + p01 = alphaAt(x, y ), p11 = alphaAt(x+1, y ), + p02 = alphaAt(x, y+1), p12 = alphaAt(x+1, y+1); + normal[X_3D] = + -1.0 * p00 +1.0 * p10 + -2.0 * p01 +2.0 * p11 + -1.0 * p02 +1.0 * p12; + normal[Y_3D] = + -2.0 * p00 -1.0 * p10 + +0.0 * p01 +0.0 * p11 // this will be optimized out + +2.0 * p02 +1.0 * p12; + } + } else if (G_UNLIKELY(x == (_w - 1))) { + // rightmost column + if (G_UNLIKELY(y == 0)) { + // top right corner + fx *= (2.0/3.0); + fy *= (2.0/3.0); + double p00 = alphaAt(x-1,y), p10 = alphaAt(x, y), + p01 = alphaAt(x-1,y+1), p11 = alphaAt(x, y+1); + normal[X_3D] = + -2.0 * p00 +2.0 * p10 + -1.0 * p01 +1.0 * p11; + normal[Y_3D] = + -1.0 * p00 -2.0 * p10 + +1.0 * p01 +2.0 * p11; + } else if (G_UNLIKELY(y == (_h - 1))) { + // bottom right corner + fx *= (2.0/3.0); + fy *= (2.0/3.0); + double p00 = alphaAt(x-1,y-1), p10 = alphaAt(x, y-1), + p01 = alphaAt(x-1,y ), p11 = alphaAt(x, y); + normal[X_3D] = + -1.0 * p00 +1.0 * p10 + -2.0 * p01 +2.0 * p11; + normal[Y_3D] = + -1.0 * p00 -2.0 * p10 + +1.0 * p01 +2.0 * p11; + } else { + // rightmost column + fx *= (1.0/2.0); + fy *= (1.0/3.0); + double p00 = alphaAt(x-1, y-1), p10 = alphaAt(x, y-1), + p01 = alphaAt(x-1, y ), p11 = alphaAt(x, y ), + p02 = alphaAt(x-1, y+1), p12 = alphaAt(x, y+1); + normal[X_3D] = + -1.0 * p00 +1.0 * p10 + -2.0 * p01 +2.0 * p11 + -1.0 * p02 +1.0 * p12; + normal[Y_3D] = + -1.0 * p00 -2.0 * p10 + +0.0 * p01 +0.0 * p11 + +1.0 * p02 +2.0 * p12; + } + } else { + // interior + if (G_UNLIKELY(y == 0)) { + // top row + fx *= (1.0/3.0); + fy *= (1.0/2.0); + double p00 = alphaAt(x-1, y ), p10 = alphaAt(x, y ), p20 = alphaAt(x+1, y ), + p01 = alphaAt(x-1, y+1), p11 = alphaAt(x, y+1), p21 = alphaAt(x+1, y+1); + normal[X_3D] = + -2.0 * p00 +0.0 * p10 +2.0 * p20 + -1.0 * p01 +0.0 * p11 +1.0 * p21; + normal[Y_3D] = + -1.0 * p00 -2.0 * p10 -1.0 * p20 + +1.0 * p01 +2.0 * p11 +1.0 * p21; + } else if (G_UNLIKELY(y == (_h - 1))) { + // bottom row + fx *= (1.0/3.0); + fy *= (1.0/2.0); + double p00 = alphaAt(x-1, y-1), p10 = alphaAt(x, y-1), p20 = alphaAt(x+1, y-1), + p01 = alphaAt(x-1, y ), p11 = alphaAt(x, y ), p21 = alphaAt(x+1, y ); + normal[X_3D] = + -1.0 * p00 +0.0 * p10 +1.0 * p20 + -2.0 * p01 +0.0 * p11 +2.0 * p21; + normal[Y_3D] = + -1.0 * p00 -2.0 * p10 -1.0 * p20 + +1.0 * p01 +2.0 * p11 +1.0 * p21; + } else { + // interior pixels + // note: p11 is actually unused, so we don't fetch its value + fx *= (1.0/4.0); + fy *= (1.0/4.0); + double p00 = alphaAt(x-1, y-1), p10 = alphaAt(x, y-1), p20 = alphaAt(x+1, y-1), + p01 = alphaAt(x-1, y ), p11 = 0.0, p21 = alphaAt(x+1, y ), + p02 = alphaAt(x-1, y+1), p12 = alphaAt(x, y+1), p22 = alphaAt(x+1, y+1); + normal[X_3D] = + -1.0 * p00 +0.0 * p10 +1.0 * p20 + -2.0 * p01 +0.0 * p11 +2.0 * p21 + -1.0 * p02 +0.0 * p12 +1.0 * p22; + normal[Y_3D] = + -1.0 * p00 -2.0 * p10 -1.0 * p20 + +0.0 * p01 +0.0 * p11 +0.0 * p21 + +1.0 * p02 +2.0 * p12 +1.0 * p22; + } + } + normal[X_3D] *= fx; + normal[Y_3D] *= fy; + NR::normalize_vector(normal); + return normal; + } + + unsigned char *_px; + int _w, _h, _stride; + bool _alpha; +}; + +/* +// simple pixel accessor for image surface that handles different edge wrapping modes +class PixelAccessor { +public: + typedef PixelAccessor self; + enum EdgeMode { + EDGE_PAD, + EDGE_WRAP, + EDGE_ZERO + }; + + PixelAccessor(cairo_surface_t *s, EdgeMode e) + : _surface(s) + , _px(cairo_image_surface_get_data(s)) + , _x(0), _y(0) + , _w(cairo_image_surface_get_width(s)) + , _h(cairo_image_surface_get_height(s)) + , _stride(cairo_image_surface_get_stride(s)) + , _edge_mode(e) + , _alpha(cairo_image_surface_get_format(s) == CAIRO_FORMAT_A8) + {} + + guint32 pixelAt(int x, int y) { + // This is a lot of ifs for a single pixel access. However, branch prediction + // should help us a lot, as the result of ifs is always the same for a single image. + int real_x = x, real_y = y; + switch (_edge_mode) { + case EDGE_PAD: + real_x = CLAMP(x, 0, _w-1); + real_y = CLAMP(y, 0, _h-1); + break; + case EDGE_WRAP: + real_x %= _w; + real_y %= _h; + break; + case EDGE_ZERO: + default: + if (x < 0 || x >= _w || y < 0 || y >= _h) + return 0; + break; + } + if (_alpha) { + return *(_px + real_y*_stride + real_x) << 24; + } else { + guint32 *px = reinterpret_cast<guint32*>(_px +real_y*_stride + real_x*4); + return *px; + } + } +private: + cairo_surface_t *_surface; + guint8 *_px; + int _x, _y, _w, _h, _stride; + EdgeMode _edge_mode; + bool _alpha; +};*/ + +// Some helpers for pixel manipulation +G_GNUC_CONST inline gint32 +pxclamp(gint32 v, gint32 low, gint32 high) { + // NOTE: it is possible to write a "branchless" clamping operation. + // However, it will be slower than this function, because the code below + // is compiled to conditional moves. + if (v < low) return low; + if (v > high) return high; + return v; +} + +#endif +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp new file mode 100644 index 000000000..90f65c33e --- /dev/null +++ b/src/display/cairo-utils.cpp @@ -0,0 +1,700 @@ +/* + * Helper functions to use cairo with inkscape + * + * Copyright (C) 2007 bulia byak + * Copyright (C) 2008 Johan Engelen + * + * Released under GNU GPL + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "display/cairo-utils.h" + +#include <stdexcept> +#include <2geom/pathvector.h> +#include <2geom/bezier-curve.h> +#include <2geom/hvlinesegment.h> +#include <2geom/affine.h> +#include <2geom/point.h> +#include <2geom/path.h> +#include <2geom/transforms.h> +#include <2geom/sbasis-to-bezier.h> +#include "color.h" +#include "helper/geom-curves.h" + +namespace Inkscape { + +CairoGroup::CairoGroup(cairo_t *_ct) : ct(_ct), pushed(false) {} +CairoGroup::~CairoGroup() { + if (pushed) { + cairo_pattern_t *p = cairo_pop_group(ct); + cairo_pattern_destroy(p); + } +} +void CairoGroup::push() { + cairo_push_group(ct); + pushed = true; +} +void CairoGroup::push_with_content(cairo_content_t content) { + cairo_push_group_with_content(ct, content); + pushed = true; +} +cairo_pattern_t *CairoGroup::pop() { + if (pushed) { + cairo_pattern_t *ret = cairo_pop_group(ct); + pushed = false; + return ret; + } else { + throw std::logic_error("Cairo group popped without pushing it first"); + } +} +Cairo::RefPtr<Cairo::Pattern> CairoGroup::popmm() { + if (pushed) { + cairo_pattern_t *ret = cairo_pop_group(ct); + Cairo::RefPtr<Cairo::Pattern> retmm(new Cairo::Pattern(ret, true)); + pushed = false; + return retmm; + } else { + throw std::logic_error("Cairo group popped without pushing it first"); + } +} +void CairoGroup::pop_to_source() { + if (pushed) { + cairo_pop_group_to_source(ct); + pushed = false; + } +} + +CairoContext::CairoContext(cairo_t *obj, bool ref) + : Cairo::Context(obj, ref) +{} + +void CairoContext::transform(Geom::Affine const &m) +{ + cairo_matrix_t cm; + cm.xx = m[0]; + cm.xy = m[2]; + cm.x0 = m[4]; + cm.yx = m[1]; + cm.yy = m[3]; + cm.y0 = m[5]; + cairo_transform(cobj(), &cm); +} + +void CairoContext::set_source_rgba32(guint32 color) +{ + double red = SP_RGBA32_R_F(color); + double gre = SP_RGBA32_G_F(color); + double blu = SP_RGBA32_B_F(color); + double alp = SP_RGBA32_A_F(color); + cairo_set_source_rgba(cobj(), red, gre, blu, alp); +} + +void CairoContext::append_path(Geom::PathVector const &pv) +{ + feed_pathvector_to_cairo(cobj(), pv); +} + +Cairo::RefPtr<CairoContext> CairoContext::create(Cairo::RefPtr<Cairo::Surface> const &target) +{ + cairo_t *ct = cairo_create(target->cobj()); + Cairo::RefPtr<CairoContext> ret(new CairoContext(ct, true)); + return ret; +} + +} // namespace Inkscape + +/* + * Can be called recursively. + * If optimize_stroke == false, the view Rect is not used. + */ +static void +feed_curve_to_cairo(cairo_t *cr, Geom::Curve const &c, Geom::Affine const & trans, Geom::Rect view, bool optimize_stroke) +{ + if( is_straight_curve(c) ) + { + Geom::Point end_tr = c.finalPoint() * trans; + if (!optimize_stroke) { + cairo_line_to(cr, end_tr[0], end_tr[1]); + } else { + Geom::Rect swept(c.initialPoint()*trans, end_tr); + if (swept.intersects(view)) { + cairo_line_to(cr, end_tr[0], end_tr[1]); + } else { + cairo_move_to(cr, end_tr[0], end_tr[1]); + } + } + } + else if(Geom::QuadraticBezier const *quadratic_bezier = dynamic_cast<Geom::QuadraticBezier const*>(&c)) { + std::vector<Geom::Point> points = quadratic_bezier->points(); + points[0] *= trans; + points[1] *= trans; + points[2] *= trans; + Geom::Point b1 = points[0] + (2./3) * (points[1] - points[0]); + Geom::Point b2 = b1 + (1./3) * (points[2] - points[0]); + if (!optimize_stroke) { + cairo_curve_to(cr, b1[0], b1[1], b2[0], b2[1], points[2][0], points[2][1]); + } else { + Geom::Rect swept(points[0], points[2]); + swept.expandTo(points[1]); + if (swept.intersects(view)) { + cairo_curve_to(cr, b1[0], b1[1], b2[0], b2[1], points[2][0], points[2][1]); + } else { + cairo_move_to(cr, points[2][0], points[2][1]); + } + } + } + else if(Geom::CubicBezier const *cubic_bezier = dynamic_cast<Geom::CubicBezier const*>(&c)) { + std::vector<Geom::Point> points = cubic_bezier->points(); + //points[0] *= trans; // don't do this one here for fun: it is only needed for optimized strokes + points[1] *= trans; + points[2] *= trans; + points[3] *= trans; + if (!optimize_stroke) { + cairo_curve_to(cr, points[1][0], points[1][1], points[2][0], points[2][1], points[3][0], points[3][1]); + } else { + points[0] *= trans; // didn't transform this point yet + Geom::Rect swept(points[0], points[3]); + swept.expandTo(points[1]); + swept.expandTo(points[2]); + if (swept.intersects(view)) { + cairo_curve_to(cr, points[1][0], points[1][1], points[2][0], points[2][1], points[3][0], points[3][1]); + } else { + cairo_move_to(cr, points[3][0], points[3][1]); + } + } + } +// else if(Geom::SVGEllipticalArc const *svg_elliptical_arc = dynamic_cast<Geom::SVGEllipticalArc *>(c)) { +// //TODO: get at the innards and spit them out to cairo +// } + else { + //this case handles sbasis as well as all other curve types + Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(c.toSBasis(), 0.1); + + //recurse to convert the new path resulting from the sbasis to svgd + for(Geom::Path::iterator iter = sbasis_path.begin(); iter != sbasis_path.end(); ++iter) { + feed_curve_to_cairo(cr, *iter, trans, view, optimize_stroke); + } + } +} + + +/** Feeds path-creating calls to the cairo context translating them from the Path */ +static void +feed_path_to_cairo (cairo_t *ct, Geom::Path const &path) +{ + if (path.empty()) + return; + + cairo_move_to(ct, path.initialPoint()[0], path.initialPoint()[1] ); + + for(Geom::Path::const_iterator cit = path.begin(); cit != path.end_open(); ++cit) { + feed_curve_to_cairo(ct, *cit, Geom::identity(), Geom::Rect(), false); // optimize_stroke is false, so the view rect is not used + } + + if (path.closed()) { + cairo_close_path(ct); + } +} + +/** Feeds path-creating calls to the cairo context translating them from the Path, with the given transform and shift */ +static void +feed_path_to_cairo (cairo_t *ct, Geom::Path const &path, Geom::Affine trans, Geom::OptRect area, bool optimize_stroke, double stroke_width) +{ + if (!area) + return; + if (path.empty()) + return; + + // Transform all coordinates to coords within "area" + Geom::Point shift = area->min(); + Geom::Rect view = *area; + view.expandBy (stroke_width); + view = view * (Geom::Affine)Geom::Translate(-shift); + // Pass transformation to feed_curve, so that we don't need to create a whole new path. + Geom::Affine transshift(trans * Geom::Translate(-shift)); + + Geom::Point initial = path.initialPoint() * transshift; + cairo_move_to(ct, initial[0], initial[1] ); + + for(Geom::Path::const_iterator cit = path.begin(); cit != path.end_open(); ++cit) { + feed_curve_to_cairo(ct, *cit, transshift, view, optimize_stroke); + } + + if (path.closed()) { + if (!optimize_stroke) { + cairo_close_path(ct); + } else { + cairo_line_to(ct, initial[0], initial[1]); + /* We cannot use cairo_close_path(ct) here because some parts of the path may have been + clipped and not drawn (maybe the before last segment was outside view area), which + would result in closing the "subpath" after the last interruption, not the entire path. + + However, according to cairo documentation: + The behavior of cairo_close_path() is distinct from simply calling cairo_line_to() with the equivalent coordinate + in the case of stroking. When a closed sub-path is stroked, there are no caps on the ends of the sub-path. Instead, + there is a line join connecting the final and initial segments of the sub-path. + + The correct fix will be possible when cairo introduces methods for moving without + ending/starting subpaths, which we will use for skipping invisible segments; then we + will be able to use cairo_close_path here. This issue also affects ps/eps/pdf export, + see bug 168129 + */ + } + } +} + +/** Feeds path-creating calls to the cairo context translating them from the PathVector, with the given transform and shift + * One must have done cairo_new_path(ct); before calling this function. */ +void +feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv, Geom::Affine trans, Geom::OptRect area, bool optimize_stroke, double stroke_width) +{ + if (!area) + return; + if (pathv.empty()) + return; + + for(Geom::PathVector::const_iterator it = pathv.begin(); it != pathv.end(); ++it) { + feed_path_to_cairo(ct, *it, trans, area, optimize_stroke, stroke_width); + } +} + +/** Feeds path-creating calls to the cairo context translating them from the PathVector + * One must have done cairo_new_path(ct); before calling this function. */ +void +feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv) +{ + if (pathv.empty()) + return; + + for(Geom::PathVector::const_iterator it = pathv.begin(); it != pathv.end(); ++it) { + feed_path_to_cairo(ct, *it); + } +} + +void +ink_cairo_set_source_rgba32(cairo_t *ct, guint32 rgba) +{ + cairo_set_source_rgba(ct, SP_RGBA32_R_F(rgba), SP_RGBA32_G_F(rgba), SP_RGBA32_B_F(rgba), SP_RGBA32_A_F(rgba)); +} + +void +ink_cairo_set_source_color(cairo_t *ct, SPColor const &c, double opacity) +{ + cairo_set_source_rgba(ct, c.v.c[0], c.v.c[1], c.v.c[2], opacity); +} + +void ink_matrix_to_2geom(Geom::Affine &m, cairo_matrix_t const &cm) +{ + m[0] = cm.xx; + m[2] = cm.xy; + m[4] = cm.x0; + m[1] = cm.yx; + m[3] = cm.yy; + m[5] = cm.y0; +} + +void ink_matrix_to_cairo(cairo_matrix_t &cm, Geom::Affine const &m) +{ + cm.xx = m[0]; + cm.xy = m[2]; + cm.x0 = m[4]; + cm.yx = m[1]; + cm.yy = m[3]; + cm.y0 = m[5]; +} + +void +ink_cairo_transform(cairo_t *ct, Geom::Affine const &m) +{ + cairo_matrix_t cm; + ink_matrix_to_cairo(cm, m); + cairo_transform(ct, &cm); +} + +void +ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m) +{ + cairo_matrix_t cm; + ink_matrix_to_cairo(cm, m); + cairo_pattern_set_matrix(cp, &cm); +} + +void +ink_cairo_set_source_argb32_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y) +{ + cairo_surface_t *pbs = ink_cairo_surface_create_for_argb32_pixbuf(pb); + cairo_set_source_surface(ct, pbs, x, y); + cairo_surface_destroy(pbs); +} + +cairo_surface_t * +ink_cairo_surface_create_for_argb32_pixbuf(GdkPixbuf *pb) +{ + guchar *data = gdk_pixbuf_get_pixels(pb); + int w = gdk_pixbuf_get_width(pb); + int h = gdk_pixbuf_get_height(pb); + int stride = gdk_pixbuf_get_rowstride(pb); + + cairo_surface_t *pbs = cairo_image_surface_create_for_data( + data, CAIRO_FORMAT_ARGB32, w, h, stride); + return pbs; +} + +/** @brief Create an exact copy of a surface. + * Creates a surface that has the same type, content type, dimensions and contents + * as the specified surface. */ +cairo_surface_t * +ink_cairo_surface_copy(cairo_surface_t *s) +{ + cairo_surface_t *ns = ink_cairo_surface_create_identical(s); + + if (cairo_surface_get_type(s) == CAIRO_SURFACE_TYPE_IMAGE) { + // use memory copy instead of using a Cairo context + cairo_surface_flush(s); + int stride = cairo_image_surface_get_stride(s); + int h = cairo_image_surface_get_height(s); + memcpy(cairo_image_surface_get_data(ns), cairo_image_surface_get_data(s), stride * h); + cairo_surface_mark_dirty(ns); + } else { + // generic implementation + cairo_t *ct = cairo_create(ns); + cairo_set_source_surface(ct, s, 0, 0); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); + cairo_destroy(ct); + } + + return ns; +} + +/** @brief Create a surface that differs only in pixel content. + * Creates a surface that has the same type, content type and dimensions + * as the specified surface. Pixel contents are not copied. */ +cairo_surface_t * +ink_cairo_surface_create_identical(cairo_surface_t *s) +{ + cairo_surface_t *ns = ink_cairo_surface_create_same_size(s, cairo_surface_get_content(s)); + return ns; +} + +cairo_surface_t * +ink_cairo_surface_create_same_size(cairo_surface_t *s, cairo_content_t c) +{ + cairo_surface_t *ns = cairo_surface_create_similar(s, c, + ink_cairo_surface_get_width(s), ink_cairo_surface_get_height(s)); + return ns; +} + +/** @brief Extract the alpha channel into a new surface. + * Creates a surface with a content type of CAIRO_CONTENT_ALPHA that contains + * the alpha values of pixels from @a s. */ +cairo_surface_t * +ink_cairo_extract_alpha(cairo_surface_t *s) +{ + cairo_surface_t *alpha = ink_cairo_surface_create_same_size(s, CAIRO_CONTENT_ALPHA); + + cairo_t *ct = cairo_create(alpha); + cairo_set_source_surface(ct, s, 0, 0); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); + cairo_destroy(ct); + + return alpha; +} + +cairo_surface_t * +ink_cairo_surface_create_output(cairo_surface_t *image, cairo_surface_t *bg) +{ + cairo_content_t imgt = cairo_surface_get_content(image); + cairo_content_t bgt = cairo_surface_get_content(bg); + cairo_surface_t *out = NULL; + + if (bgt == CAIRO_CONTENT_ALPHA && imgt == CAIRO_CONTENT_ALPHA) { + out = ink_cairo_surface_create_identical(bg); + } else { + out = ink_cairo_surface_create_same_size(bg, CAIRO_CONTENT_COLOR_ALPHA); + } + + return out; +} + +void +ink_cairo_surface_blit(cairo_surface_t *src, cairo_surface_t *dest) +{ + if (cairo_surface_get_type(src) == CAIRO_SURFACE_TYPE_IMAGE && + cairo_surface_get_type(dest) == CAIRO_SURFACE_TYPE_IMAGE && + cairo_image_surface_get_format(src) == cairo_image_surface_get_format(dest) && + cairo_image_surface_get_height(src) == cairo_image_surface_get_height(dest) && + cairo_image_surface_get_width(src) == cairo_image_surface_get_width(dest) && + cairo_image_surface_get_stride(src) == cairo_image_surface_get_stride(dest)) + { + // use memory copy instead of using a Cairo context + cairo_surface_flush(src); + int stride = cairo_image_surface_get_stride(src); + int h = cairo_image_surface_get_height(src); + memcpy(cairo_image_surface_get_data(dest), cairo_image_surface_get_data(src), stride * h); + cairo_surface_mark_dirty(dest); + } else { + // generic implementation + cairo_t *ct = cairo_create(dest); + cairo_set_source_surface(ct, src, 0, 0); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); + cairo_destroy(ct); + } +} + +int +ink_cairo_surface_get_width(cairo_surface_t *surface) +{ + // For now only image surface is handled. + // Later add others, e.g. cairo-gl + assert(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE); + return cairo_image_surface_get_width(surface); +} +int +ink_cairo_surface_get_height(cairo_surface_t *surface) +{ + assert(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE); + return cairo_image_surface_get_height(surface); +} + +static int ink_cairo_surface_average_color_internal(cairo_surface_t *surface, double &rf, double &gf, double &bf, double &af) +{ + rf = gf = bf = af = 0.0; + cairo_surface_flush(surface); + int width = cairo_image_surface_get_width(surface); + int height = cairo_image_surface_get_height(surface); + int stride = cairo_image_surface_get_stride(surface); + unsigned char *data = cairo_image_surface_get_data(surface); + + /* TODO convert this to OpenMP somehow */ + for (int y = 0; y < height; ++y, data += stride) { + for (int x = 0; x < width; ++x) { + guint32 px = *reinterpret_cast<guint32*>(data + 4*x); + EXTRACT_ARGB32(px, a,r,g,b) + rf += r / 255.0; + gf += g / 255.0; + bf += b / 255.0; + af += a / 255.0; + } + } + return width * height; +} + +guint32 ink_cairo_surface_average_color(cairo_surface_t *surface) +{ + double rf,gf,bf,af; + ink_cairo_surface_average_color_premul(surface, rf,gf,bf,af); + guint32 r = round(rf * 255); + guint32 g = round(gf * 255); + guint32 b = round(bf * 255); + guint32 a = round(af * 255); + ASSEMBLE_ARGB32(px, a,r,g,b); + return px; +} + +void ink_cairo_surface_average_color(cairo_surface_t *surface, double &r, double &g, double &b, double &a) +{ + int count = ink_cairo_surface_average_color_internal(surface, r,g,b,a); + + r /= a; + g /= a; + b /= a; + a /= count; + + r = CLAMP(r, 0.0, 1.0); + g = CLAMP(g, 0.0, 1.0); + b = CLAMP(b, 0.0, 1.0); + a = CLAMP(a, 0.0, 1.0); +} + +void ink_cairo_surface_average_color_premul(cairo_surface_t *surface, double &r, double &g, double &b, double &a) +{ + int count = ink_cairo_surface_average_color_internal(surface, r,g,b,a); + + r /= count; + g /= count; + b /= count; + a /= count; + + r = CLAMP(r, 0.0, 1.0); + g = CLAMP(g, 0.0, 1.0); + b = CLAMP(b, 0.0, 1.0); + a = CLAMP(a, 0.0, 1.0); +} + +cairo_pattern_t * +ink_cairo_pattern_create_checkerboard() +{ + int const w = 6; + int const h = 6; + + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 2*w, 2*h); + + cairo_t *ct = cairo_create(s); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgb(ct, 0.75, 0.75, 0.75); + cairo_paint(ct); + cairo_set_source_rgb(ct, 0.5, 0.5, 0.5); + cairo_rectangle(ct, 0, 0, w, h); + cairo_rectangle(ct, w, h, w, h); + cairo_fill(ct); + cairo_destroy(ct); + + cairo_pattern_t *p = cairo_pattern_create_for_surface(s); + cairo_pattern_set_extend(p, CAIRO_EXTEND_REPEAT); + cairo_pattern_set_filter(p, CAIRO_FILTER_NEAREST); + + cairo_surface_destroy(s); + return p; +} + +/* The following two functions use "from" instead of "to", because when you write: + val1 = argb32_from_pixbuf(val1); + the name of the format is closer to the value in that format. */ + +guint32 argb32_from_pixbuf(guint32 c) +{ + guint32 o = 0; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + guint32 a = (c & 0xff000000) >> 24; +#else + guint32 a = (c & 0x000000ff); +#endif + if (a != 0) { + // extract color components +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + guint32 r = (c & 0x000000ff); + guint32 g = (c & 0x0000ff00) >> 8; + guint32 b = (c & 0x00ff0000) >> 16; +#else + guint32 r = (c & 0xff000000) >> 24; + guint32 g = (c & 0x00ff0000) >> 16; + guint32 b = (c & 0x0000ff00) >> 8; +#endif + // premultiply + r = premul_alpha(r, a); + b = premul_alpha(b, a); + g = premul_alpha(g, a); + // combine into output + o = (a << 24) | (r << 16) | (g << 8) | (b); + } + return o; +} + +guint32 pixbuf_from_argb32(guint32 c) +{ + guint32 a = (c & 0xff000000) >> 24; + if (a == 0) return 0; + + // extract color components + guint32 r = (c & 0x00ff0000) >> 16; + guint32 g = (c & 0x0000ff00) >> 8; + guint32 b = (c & 0x000000ff); + // unpremultiply; adding a/2 gives correct rounding + // (taken from Cairo sources) + r = (r * 255 + a/2) / a; + b = (b * 255 + a/2) / a; + g = (g * 255 + a/2) / a; + // combine into output +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + guint32 o = (r) | (g << 8) | (b << 16) | (a << 24); +#else + guint32 o = (r << 24) | (g << 16) | (b << 8) | (a); +#endif + return o; +} + +/** + * @brief Convert pixel data from GdkPixbuf format to ARGB. + * This will convert pixel data from GdkPixbuf format to Cairo's native pixel format. + * This involves premultiplying alpha and shuffling around the channels. + * Pixbuf data must have an alpha channel, otherwise the results are undefined + * (usually a segfault). + */ +void +convert_pixels_pixbuf_to_argb32(guchar *data, int w, int h, int stride) +{ + for (int i = 0; i < h; ++i) { + guint32 *px = reinterpret_cast<guint32*>(data + i*stride); + for (int j = 0; j < w; ++j) { + *px = argb32_from_pixbuf(*px); + ++px; + } + } +} + +/** + * @brief Convert pixel data from ARGB to GdkPixbuf format. + * This will convert pixel data from GdkPixbuf format to Cairo's native pixel format. + * This involves premultiplying alpha and shuffling around the channels. + */ +void +convert_pixels_argb32_to_pixbuf(guchar *data, int w, int h, int stride) +{ + for (int i = 0; i < h; ++i) { + guint32 *px = reinterpret_cast<guint32*>(data + i*stride); + for (int j = 0; j < w; ++j) { + *px = pixbuf_from_argb32(*px); + ++px; + } + } +} + +/** + * @brief Converts GdkPixbuf's data to premultiplied ARGB. + * This function will convert a GdkPixbuf in place into Cairo's native pixel format. + * Note that this is a hack intended to save memory. When the pixbuf is in Cairo's format, + * using it with GTK will result in corrupted drawings. + */ +void +convert_pixbuf_normal_to_argb32(GdkPixbuf *pb) +{ + convert_pixels_pixbuf_to_argb32( + gdk_pixbuf_get_pixels(pb), + gdk_pixbuf_get_width(pb), + gdk_pixbuf_get_height(pb), + gdk_pixbuf_get_rowstride(pb)); +} + +/** + * @brief Converts GdkPixbuf's data back to its native format. + * Once this is done, the pixbuf can be used with GTK again. + */ +void +convert_pixbuf_argb32_to_normal(GdkPixbuf *pb) +{ + convert_pixels_argb32_to_pixbuf( + gdk_pixbuf_get_pixels(pb), + gdk_pixbuf_get_width(pb), + gdk_pixbuf_get_height(pb), + gdk_pixbuf_get_rowstride(pb)); +} + +guint32 argb32_from_rgba(guint32 in) +{ + guint32 r, g, b, a; + a = (in & 0x000000ff); + r = premul_alpha((in & 0xff000000) >> 24, a); + g = premul_alpha((in & 0x00ff0000) >> 16, a); + b = premul_alpha((in & 0x0000ff00) >> 8, a); + ASSEMBLE_ARGB32(px, a, r, g, b) + return px; +} + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/display/cairo-utils.h b/src/display/cairo-utils.h new file mode 100644 index 000000000..0c2ac2dd6 --- /dev/null +++ b/src/display/cairo-utils.h @@ -0,0 +1,153 @@ +/** + * @file + * @brief Cairo integration helpers + *//* + * Authors: + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * + * Copyright (C) 2010 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_CAIRO_UTILS_H +#define SEEN_INKSCAPE_DISPLAY_CAIRO_UTILS_H + +#include <glib.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <cairomm/cairomm.h> +#include <2geom/forward.h> + +struct SPColor; + +namespace Inkscape { + +/** @brief RAII idiom for Cairo groups. + * Groups are temporary surfaces used when rendering e.g. masks and opacity. + * Use this class to ensure that each group push is matched with a pop. */ +class CairoGroup { +public: + CairoGroup(cairo_t *_ct); + ~CairoGroup(); + void push(); + void push_with_content(cairo_content_t content); + cairo_pattern_t *pop(); + Cairo::RefPtr<Cairo::Pattern> popmm(); + void pop_to_source(); +private: + cairo_t *ct; + bool pushed; +}; + +/** @brief RAII idiom for Cairo state saving */ +class CairoSave { +public: + CairoSave(cairo_t *_ct, bool save=false) + : ct(_ct) + , saved(save) + { + if (save) { + cairo_save(ct); + } + } + void save() { + if (!saved) { + cairo_save(ct); + saved = true; + } + } + ~CairoSave() { + if (saved) + cairo_restore(ct); + } +private: + cairo_t *ct; + bool saved; +}; + +/** @brief Cairo context with Inkscape-specific operations */ +class CairoContext : public Cairo::Context { +public: + CairoContext(cairo_t *obj, bool ref = false); + + void transform(Geom::Affine const &m); + void set_source_rgba32(guint32 color); + void append_path(Geom::PathVector const &pv); + + static Cairo::RefPtr<CairoContext> create(Cairo::RefPtr<Cairo::Surface> const &target); +}; + +} // namespace Inkscape + +void ink_cairo_set_source_color(cairo_t *ct, SPColor const &color, double opacity); +void ink_cairo_set_source_rgba32(cairo_t *ct, guint32 rgba); +void ink_cairo_transform(cairo_t *ct, Geom::Affine const &m); +void ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m); +void ink_cairo_set_source_argb32_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y); + +void ink_matrix_to_2geom(Geom::Affine &, cairo_matrix_t const &); +void ink_matrix_to_cairo(cairo_matrix_t &, Geom::Affine const &); + +cairo_surface_t *ink_cairo_surface_copy(cairo_surface_t *s); +cairo_surface_t *ink_cairo_surface_create_identical(cairo_surface_t *s); +cairo_surface_t *ink_cairo_surface_create_same_size(cairo_surface_t *s, cairo_content_t c); +cairo_surface_t *ink_cairo_extract_alpha(cairo_surface_t *s); +cairo_surface_t *ink_cairo_surface_create_output(cairo_surface_t *image, cairo_surface_t *bg); +void ink_cairo_surface_blit(cairo_surface_t *src, cairo_surface_t *dest); +int ink_cairo_surface_get_width(cairo_surface_t *surface); +int ink_cairo_surface_get_height(cairo_surface_t *surface); +guint32 ink_cairo_surface_average_color(cairo_surface_t *surface); +void ink_cairo_surface_average_color(cairo_surface_t *surface, double &r, double &g, double &b, double &a); +void ink_cairo_surface_average_color_premul(cairo_surface_t *surface, double &r, double &g, double &b, double &a); + +cairo_pattern_t *ink_cairo_pattern_create_checkerboard(); + +void convert_pixels_pixbuf_to_argb32(guchar *data, int w, int h, int rs); +void convert_pixels_argb32_to_pixbuf(guchar *data, int w, int h, int rs); +void convert_pixbuf_normal_to_argb32(GdkPixbuf *); +void convert_pixbuf_argb32_to_normal(GdkPixbuf *); +cairo_surface_t *ink_cairo_surface_create_for_argb32_pixbuf(GdkPixbuf *pb); + +G_GNUC_CONST guint32 argb32_from_pixbuf(guint32 in); +G_GNUC_CONST guint32 pixbuf_from_argb32(guint32 in); +/** Convert a pixel in 0xRRGGBBAA format to Cairo ARGB32 format. */ +G_GNUC_CONST guint32 argb32_from_rgba(guint32 in); + + +G_GNUC_CONST inline guint32 +premul_alpha(guint32 color, guint32 alpha) +{ + guint32 temp = alpha * color + 128; + return (temp + (temp >> 8)) >> 8; +} +G_GNUC_CONST inline guint32 +unpremul_alpha(guint32 color, guint32 alpha) +{ + // NOTE: you must check for alpha != 0 yourself. + return (255 * color + alpha/2) / alpha; +} + +// TODO: move those to 2Geom +void feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv, Geom::Affine trans, Geom::OptRect area, bool optimize_stroke, double stroke_width); +void feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv); + +#define EXTRACT_ARGB32(px,a,r,g,b) \ + guint32 a, r, g, b; \ + a = ((px) & 0xff000000) >> 24; \ + r = ((px) & 0x00ff0000) >> 16; \ + g = ((px) & 0x0000ff00) >> 8; \ + b = ((px) & 0x000000ff); + +#define ASSEMBLE_ARGB32(px,a,r,g,b) \ + guint32 px = (a << 24) | (r << 16) | (g << 8) | b; + +#endif +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp index 8436a3b99..72062ce99 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -10,15 +10,15 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <libnr/nr-blit.h> #include <gtk/gtk.h> -#include <display/sp-canvas-util.h> +#include "display/display-forward.h" +#include "display/sp-canvas-util.h" #include "helper/sp-marshal.h" -#include <display/nr-arena.h> -#include <display/nr-arena-group.h> -#include <display/canvas-arena.h> -#include <display/inkscape-cairo.h> +#include "display/nr-arena.h" +#include "display/nr-arena-group.h" +#include "display/canvas-arena.h" +#include "display/cairo-utils.h" enum { ARENA_EVENT, @@ -188,6 +188,7 @@ sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf) gint bw, bh; SPCanvasArena *arena = SP_CANVAS_ARENA (item); + //SPCanvas *canvas = item->canvas; nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_RENDER, @@ -200,28 +201,17 @@ sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf) if ((bw < 1) || (bh < 1)) return; NRRectL area; - NRPixBlock cb; area.x0 = buf->rect.x0; area.y0 = buf->rect.y0; area.x1 = buf->rect.x1; area.y1 = buf->rect.y1; - nr_pixblock_setup_extern (&cb, NR_PIXBLOCK_MODE_R8G8B8A8P, area.x0, area.y0, area.x1, area.y1, - buf->buf, - buf->buf_rowstride, - FALSE, FALSE); - - cb.visible_area = buf->visible_rect; - cairo_t *ct = nr_create_cairo_context (&area, &cb); - nr_arena_item_invoke_render (ct, arena->root, &area, &cb, 0); - - cairo_surface_t *cst = cairo_get_target(ct); - cairo_destroy (ct); - cairo_surface_finish (cst); - cairo_surface_destroy (cst); - - nr_pixblock_release (&cb); + sp_canvas_prepare_buffer(buf); + cairo_save(buf->ct); + cairo_translate(buf->ct, -area.x0, -area.y0); + nr_arena_item_invoke_render (buf->ct, arena->root, &area, NULL, 0); + cairo_restore(buf->ct); } static double @@ -368,22 +358,15 @@ sp_canvas_arena_set_sticky (SPCanvasArena *ca, gboolean sticky) } void -sp_canvas_arena_render_pixblock (SPCanvasArena *ca, NRPixBlock *pb) +sp_canvas_arena_render_surface (SPCanvasArena *ca, cairo_surface_t *surface, NRRectL const &r) { - NRRectL area; - g_return_if_fail (ca != NULL); g_return_if_fail (SP_IS_CANVAS_ARENA (ca)); - /* fixme: */ - pb->empty = FALSE; - - area.x0 = pb->area.x0; - area.y0 = pb->area.y0; - area.x1 = pb->area.x1; - area.y1 = pb->area.y1; - - nr_arena_item_invoke_render (NULL, ca->root, &area, pb, 0); + cairo_t *ct = cairo_create(surface); + cairo_translate(ct, -r.x0, -r.y0); + nr_arena_item_invoke_render (ct, ca->root, &r, NULL, 0); + cairo_destroy(ct); } diff --git a/src/display/canvas-arena.h b/src/display/canvas-arena.h index 90be5f9e3..ef065a03b 100644 --- a/src/display/canvas-arena.h +++ b/src/display/canvas-arena.h @@ -13,8 +13,11 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "sp-canvas-item.h" -#include "nr-arena-item.h" +#include <cairo.h> +#include <2geom/rect.h> +#include "display/sp-canvas.h" +#include "display/sp-canvas-item.h" +#include "display/nr-arena-item.h" G_BEGIN_DECLS @@ -55,7 +58,7 @@ GtkType sp_canvas_arena_get_type (void); void sp_canvas_arena_set_pick_delta (SPCanvasArena *ca, gdouble delta); void sp_canvas_arena_set_sticky (SPCanvasArena *ca, gboolean sticky); -void sp_canvas_arena_render_pixblock (SPCanvasArena *ca, NRPixBlock *pb); +void sp_canvas_arena_render_surface (SPCanvasArena *ca, cairo_surface_t *surface, NRRectL const &area); G_END_DECLS diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp index 845c4e077..a9893f09d 100644 --- a/src/display/canvas-axonomgrid.cpp +++ b/src/display/canvas-axonomgrid.cpp @@ -15,25 +15,24 @@ * For example: the line drawing code should not be here. There _must_ be a function somewhere else that can provide this functionality... */ -#include "sp-canvas-util.h" -#include "canvas-axonomgrid.h" -#include "util/mathfns.h" #include "2geom/line.h" -#include <libnr/nr-pixops.h> - +#include "desktop.h" #include "canvas-grid.h" #include "desktop-handles.h" +#include "display/cairo-utils.h" +#include "display/canvas-axonomgrid.h" +#include "display/canvas-grid.h" +#include "display/display-forward.h" +#include "display/sp-canvas-util.h" +#include "document.h" #include "helper/units.h" -#include "svg/svg-color.h" -#include "xml/node-event-vector.h" -#include "sp-object.h" - -#include "sp-namedview.h" #include "inkscape.h" -#include "desktop.h" - -#include "document.h" #include "preferences.h" +#include "sp-namedview.h" +#include "sp-object.h" +#include "svg/svg-color.h" +#include "util/mathfns.h" +#include "xml/node-event-vector.h" #define SAFE_SETPIXEL //undefine this when it is certain that setpixel is never called with invalid params @@ -45,37 +44,6 @@ enum Dim3 { X=0, Y, Z }; static double deg_to_rad(double deg) { return deg*M_PI/180.0;} - -/** - \brief This function renders a pixel on a particular buffer. - - The topleft of the buffer equals - ( rect.x0 , rect.y0 ) in screen coordinates - ( 0 , 0 ) in setpixel coordinates - The bottomright of the buffer equals - ( rect.x1 , rect,y1 ) in screen coordinates - ( rect.x1 - rect.x0 , rect.y1 - rect.y0 ) in setpixel coordinates -*/ -static void -sp_caxonomgrid_setpixel (SPCanvasBuf *buf, gint x, gint y, guint32 rgba) -{ -#ifdef SAFE_SETPIXEL - if ( (x >= buf->rect.x0) && (x < buf->rect.x1) && (y >= buf->rect.y0) && (y < buf->rect.y1) ) { -#endif - guint r, g, b, a; - r = NR_RGBA32_R (rgba); - g = NR_RGBA32_G (rgba); - b = NR_RGBA32_B (rgba); - a = NR_RGBA32_A (rgba); - guchar * p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x - buf->rect.x0) * 4; - p[0] = NR_COMPOSEN11_1111 (r, a, p[0]); - p[1] = NR_COMPOSEN11_1111 (g, a, p[1]); - p[2] = NR_COMPOSEN11_1111 (b, a, p[2]); -#ifdef SAFE_SETPIXEL - } -#endif -} - /** \brief This function renders a line on a particular canvas buffer, using Bresenham's line drawing function. @@ -85,6 +53,12 @@ sp_caxonomgrid_setpixel (SPCanvasBuf *buf, gint x, gint y, guint32 rgba) static void sp_caxonomgrid_drawline (SPCanvasBuf *buf, gint x0, gint y0, gint x1, gint y1, guint32 rgba) { + cairo_move_to(buf->ct, 0.5 + x0, 0.5 + y0); + cairo_line_to(buf->ct, 0.5 + x1, 0.5 + y1); + ink_cairo_set_source_rgba32(buf->ct, rgba); + cairo_stroke(buf->ct); + +#if 0 int dy = y1 - y0; int dx = x1 - x0; int stepx, stepy; @@ -118,30 +92,19 @@ sp_caxonomgrid_drawline (SPCanvasBuf *buf, gint x0, gint y0, gint x1, gint y1, g sp_caxonomgrid_setpixel(buf, x0, y0, rgba); } } - +#endif } static void sp_grid_vline (SPCanvasBuf *buf, gint x, gint ys, gint ye, guint32 rgba) { - if ((x >= buf->rect.x0) && (x < buf->rect.x1)) { - guint r, g, b, a; - gint y0, y1, y; - guchar *p; - r = NR_RGBA32_R(rgba); - g = NR_RGBA32_G (rgba); - b = NR_RGBA32_B (rgba); - a = NR_RGBA32_A (rgba); - y0 = MAX (buf->rect.y0, ys); - y1 = MIN (buf->rect.y1, ye + 1); - p = buf->buf + (y0 - buf->rect.y0) * buf->buf_rowstride + (x - buf->rect.x0) * 4; - for (y = y0; y < y1; y++) { - p[0] = NR_COMPOSEN11_1111 (r, a, p[0]); - p[1] = NR_COMPOSEN11_1111 (g, a, p[1]); - p[2] = NR_COMPOSEN11_1111 (b, a, p[2]); - p += buf->buf_rowstride; - } - } + if ((x < buf->rect.x0) || (x >= buf->rect.x1)) + return; + + cairo_move_to(buf->ct, 0.5 + x, 0.5 + ys); + cairo_line_to(buf->ct, 0.5 + x, 0.5 + ye); + ink_cairo_set_source_rgba32(buf->ct, rgba); + cairo_stroke(buf->ct); } namespace Inkscape { @@ -561,6 +524,11 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf) _empcolor = empcolor; } + cairo_save(buf->ct); + cairo_translate(buf->ct, -buf->rect.x0, -buf->rect.y0); + cairo_set_line_width(buf->ct, 1.0); + cairo_set_line_cap(buf->ct, CAIRO_LINE_CAP_SQUARE); + // gc = gridcoordinates (the coordinates calculated from the grids origin 'grid->ow'. // sc = screencoordinates ( for example "buf->rect.x0" is in screencoordinates ) // bc = buffer patch coordinates @@ -658,6 +626,8 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf) sp_caxonomgrid_drawline (buf, x0, y0, x1, y1, _empcolor); } } + + cairo_restore(buf->ct); } CanvasAxonomGridSnapper::CanvasAxonomGridSnapper(CanvasAxonomGrid *grid, SnapManager *sm, Geom::Coord const d) : LineSnapper(sm, d) diff --git a/src/display/canvas-bpath.cpp b/src/display/canvas-bpath.cpp index 725a1d0ff..f86743744 100644 --- a/src/display/canvas-bpath.cpp +++ b/src/display/canvas-bpath.cpp @@ -15,19 +15,17 @@ #endif #include <sstream> #include <string.h> -#include <desktop.h> +#include "desktop.h" #include "color.h" -#include "sp-canvas-util.h" -#include "inkscape-cairo.h" -#include "canvas-bpath.h" #include "display/sp-canvas-group.h" +#include "display/sp-canvas-util.h" +#include "display/canvas-bpath.h" +#include "display/display-forward.h" #include "display/curve.h" -#include "display/inkscape-cairo.h" -#include "libnr/nr-pixops.h" +#include "display/cairo-utils.h" #include "helper/geom.h" - void nr_pixblock_render_bpath_rgba (Shape* theS,uint32_t color,NRRectL &area,char* destBuf,int stride); static void sp_canvas_bpath_class_init (SPCanvasBPathClass *klass); @@ -139,8 +137,6 @@ sp_canvas_bpath_render (SPCanvasItem *item, SPCanvasBuf *buf) { SPCanvasBPath *cbp = SP_CANVAS_BPATH (item); - sp_canvas_prepare_buffer(buf); - Geom::Rect area (Geom::Point(buf->rect.x0, buf->rect.y0), Geom::Point(buf->rect.x1, buf->rect.y1)); if ( !cbp->curve || @@ -154,33 +150,29 @@ sp_canvas_bpath_render (SPCanvasItem *item, SPCanvasBuf *buf) bool dofill = ((cbp->fill_rgba & 0xff) != 0); bool dostroke = ((cbp->stroke_rgba & 0xff) != 0); - cairo_set_tolerance(buf->ct, 1.25); // low quality, but good enough for canvas items + cairo_set_tolerance(buf->ct, 0.5); cairo_new_path(buf->ct); - if (!dofill) - feed_pathvector_to_cairo (buf->ct, cbp->curve->get_pathvector(), cbp->affine, area, true, 1); - else - feed_pathvector_to_cairo (buf->ct, cbp->curve->get_pathvector(), cbp->affine, area, false, 1); + feed_pathvector_to_cairo (buf->ct, cbp->curve->get_pathvector(), cbp->affine, area, + /* optimized_stroke = */ !dofill, 1); if (dofill) { // RGB / BGR - cairo_set_source_rgba(buf->ct, SP_RGBA32_B_F(cbp->fill_rgba), SP_RGBA32_G_F(cbp->fill_rgba), SP_RGBA32_R_F(cbp->fill_rgba), SP_RGBA32_A_F(cbp->fill_rgba)); + ink_cairo_set_source_rgba32(buf->ct, cbp->fill_rgba); cairo_set_fill_rule(buf->ct, cbp->fill_rule == SP_WIND_RULE_EVENODD? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); - if (dostroke) - cairo_fill_preserve(buf->ct); - else - cairo_fill(buf->ct); + cairo_fill_preserve(buf->ct); } if (dostroke) { - // RGB / BGR - cairo_set_source_rgba(buf->ct, SP_RGBA32_B_F(cbp->stroke_rgba), SP_RGBA32_G_F(cbp->stroke_rgba), SP_RGBA32_R_F(cbp->stroke_rgba), SP_RGBA32_A_F(cbp->stroke_rgba)); + ink_cairo_set_source_rgba32(buf->ct, cbp->stroke_rgba); cairo_set_line_width(buf->ct, 1); if (cbp->dashes[0] != 0 && cbp->dashes[1] != 0) { cairo_set_dash (buf->ct, cbp->dashes, 2, 0); } cairo_stroke(buf->ct); + } else { + cairo_new_path(buf->ct); } } @@ -192,12 +184,12 @@ sp_canvas_bpath_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_ if ( !cbp->curve || ((cbp->stroke_rgba & 0xff) == 0 && (cbp->fill_rgba & 0xff) == 0 ) || cbp->curve->get_segment_count() < 1) - return NR_HUGE; + return Geom::infinity(); double width = 0.5; Geom::Rect viewbox = item->canvas->getViewbox(); viewbox.expandBy (width); - double dist = NR_HUGE; + double dist = Geom::infinity(); pathv_matrix_point_bbox_wind_distance(cbp->curve->get_pathvector(), cbp->affine, p, NULL, NULL, &dist, 0.5, &viewbox); if (dist <= 1.0) { diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index 79bfc31ad..82ea036f6 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -12,25 +12,26 @@ * Don't be shy to correct things. */ -#include "sp-canvas-group.h" +#include "desktop.h" #include "sp-canvas-util.h" #include "util/mathfns.h" -#include "libnr/nr-pixops.h" +#include "display-forward.h" #include "desktop-handles.h" +#include "display/cairo-utils.h" +#include "display/canvas-axonomgrid.h" +#include "display/canvas-grid.h" +#include "display/display-forward.h" +#include "display/sp-canvas-util.h" +#include "display/sp-canvas-group.h" +#include "document.h" #include "helper/units.h" -#include "svg/svg-color.h" -#include "xml/node-event-vector.h" -#include "sp-object.h" - -#include "sp-namedview.h" #include "inkscape.h" -#include "desktop.h" - -#include "../document.h" #include "preferences.h" - -#include "canvas-grid.h" -#include "canvas-axonomgrid.h" +#include "sp-namedview.h" +#include "sp-object.h" +#include "svg/svg-color.h" +#include "util/mathfns.h" +#include "xml/node-event-vector.h" using Inkscape::DocumentUndo; @@ -831,65 +832,86 @@ CanvasXYGrid::Update (Geom::Affine const &affine, unsigned int /*flags*/) static void grid_hline (SPCanvasBuf *buf, gint y, gint xs, gint xe, guint32 rgba) { - if ((y >= buf->rect.y0) && (y < buf->rect.y1)) { - guint r, g, b, a; - gint x0, x1, x; - guchar *p; - r = NR_RGBA32_R (rgba); - g = NR_RGBA32_G (rgba); - b = NR_RGBA32_B (rgba); - a = NR_RGBA32_A (rgba); - x0 = MAX (buf->rect.x0, xs); - x1 = MIN (buf->rect.x1, xe + 1); - p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x0 - buf->rect.x0) * 4; - for (x = x0; x < x1; x++) { - p[0] = NR_COMPOSEN11_1111 (r, a, p[0]); - p[1] = NR_COMPOSEN11_1111 (g, a, p[1]); - p[2] = NR_COMPOSEN11_1111 (b, a, p[2]); - p += 4; - } + if ((y < buf->rect.y0) || (y >= buf->rect.y1)) + return; + + cairo_move_to(buf->ct, 0.5 + xs, 0.5 + y); + cairo_line_to(buf->ct, 0.5 + xe, 0.5 + y); + ink_cairo_set_source_rgba32(buf->ct, rgba); + cairo_stroke(buf->ct); +#if 0 + guint r, g, b, a; + gint x0, x1, x; + guchar *p; + r = NR_RGBA32_R (rgba); + g = NR_RGBA32_G (rgba); + b = NR_RGBA32_B (rgba); + a = NR_RGBA32_A (rgba); + x0 = MAX (buf->rect.x0, xs); + x1 = MIN (buf->rect.x1, xe + 1); + p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x0 - buf->rect.x0) * 4; + for (x = x0; x < x1; x++) { + p[0] = NR_COMPOSEN11_1111 (r, a, p[0]); + p[1] = NR_COMPOSEN11_1111 (g, a, p[1]); + p[2] = NR_COMPOSEN11_1111 (b, a, p[2]); + p += 4; } +#endif } static void grid_vline (SPCanvasBuf *buf, gint x, gint ys, gint ye, guint32 rgba) { - if ((x >= buf->rect.x0) && (x < buf->rect.x1)) { - guint r, g, b, a; - gint y0, y1, y; - guchar *p; - r = NR_RGBA32_R(rgba); - g = NR_RGBA32_G (rgba); - b = NR_RGBA32_B (rgba); - a = NR_RGBA32_A (rgba); - y0 = MAX (buf->rect.y0, ys); - y1 = MIN (buf->rect.y1, ye + 1); - p = buf->buf + (y0 - buf->rect.y0) * buf->buf_rowstride + (x - buf->rect.x0) * 4; - for (y = y0; y < y1; y++) { - p[0] = NR_COMPOSEN11_1111 (r, a, p[0]); - p[1] = NR_COMPOSEN11_1111 (g, a, p[1]); - p[2] = NR_COMPOSEN11_1111 (b, a, p[2]); - p += buf->buf_rowstride; - } + if ((x < buf->rect.x0) || (x >= buf->rect.x1)) + return; + + cairo_move_to(buf->ct, 0.5 + x, 0.5 + ys); + cairo_line_to(buf->ct, 0.5 + x, 0.5 + ye); + ink_cairo_set_source_rgba32(buf->ct, rgba); + cairo_stroke(buf->ct); + #if 0 + guint r, g, b, a; + gint y0, y1, y; + guchar *p; + r = NR_RGBA32_R(rgba); + g = NR_RGBA32_G (rgba); + b = NR_RGBA32_B (rgba); + a = NR_RGBA32_A (rgba); + y0 = MAX (buf->rect.y0, ys); + y1 = MIN (buf->rect.y1, ye + 1); + p = buf->buf + (y0 - buf->rect.y0) * buf->buf_rowstride + (x - buf->rect.x0) * 4; + for (y = y0; y < y1; y++) { + p[0] = NR_COMPOSEN11_1111 (r, a, p[0]); + p[1] = NR_COMPOSEN11_1111 (g, a, p[1]); + p[2] = NR_COMPOSEN11_1111 (b, a, p[2]); + p += buf->buf_rowstride; } + #endif } static void grid_dot (SPCanvasBuf *buf, gint x, gint y, guint32 rgba) { - if ( (y >= buf->rect.y0) && (y < buf->rect.y1) - && (x >= buf->rect.x0) && (x < buf->rect.x1) ) { - guint r, g, b, a; - guchar *p; - r = NR_RGBA32_R (rgba); - g = NR_RGBA32_G (rgba); - b = NR_RGBA32_B (rgba); - a = NR_RGBA32_A (rgba); - p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x - buf->rect.x0) * 4; - p[0] = NR_COMPOSEN11_1111 (r, a, p[0]); - p[1] = NR_COMPOSEN11_1111 (g, a, p[1]); - p[2] = NR_COMPOSEN11_1111 (b, a, p[2]); - } + if ( (y < buf->rect.y0) || (y >= buf->rect.y1) + || (x < buf->rect.x0) || (x >= buf->rect.x1) ) + return; + + cairo_rectangle(buf->ct, x, y, 1, 1); + ink_cairo_set_source_rgba32(buf->ct, rgba); + cairo_fill(buf->ct); + +#if 0 + guint r, g, b, a; + guchar *p; + r = NR_RGBA32_R (rgba); + g = NR_RGBA32_G (rgba); + b = NR_RGBA32_B (rgba); + a = NR_RGBA32_A (rgba); + p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x - buf->rect.x0) * 4; + p[0] = NR_COMPOSEN11_1111 (r, a, p[0]); + p[1] = NR_COMPOSEN11_1111 (g, a, p[1]); + p[2] = NR_COMPOSEN11_1111 (b, a, p[2]); +#endif } void @@ -910,6 +932,11 @@ CanvasXYGrid::Render (SPCanvasBuf *buf) _empcolor = empcolor; } + cairo_save(buf->ct); + cairo_translate(buf->ct, -buf->rect.x0, -buf->rect.y0); + cairo_set_line_width(buf->ct, 1.0); + cairo_set_line_cap(buf->ct, CAIRO_LINE_CAP_SQUARE); + if (!render_dotted) { gint ylinenum; gdouble y; @@ -961,6 +988,7 @@ CanvasXYGrid::Render (SPCanvasBuf *buf) } } + cairo_restore(buf->ct); } CanvasXYGridSnapper::CanvasXYGridSnapper(CanvasXYGrid *grid, SnapManager *sm, Geom::Coord const d) : LineSnapper(sm, d) diff --git a/src/display/canvas-text.cpp b/src/display/canvas-text.cpp index 70196b307..54cbe5da8 100644 --- a/src/display/canvas-text.cpp +++ b/src/display/canvas-text.cpp @@ -13,19 +13,19 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "sp-canvas-util.h" -#include "canvas-text.h" -#include "display/inkscape-cairo.h" -#include <sstream> -#include <string.h> -#include "desktop.h" - #ifdef HAVE_CONFIG_H # include "config.h" #endif -#include <color.h> -#include <libnr/nr-pixops.h> +#include <sstream> +#include <string.h> + +#include "display-forward.h" +#include "sp-canvas-util.h" +#include "canvas-text.h" +#include "display/cairo-utils.h" +#include "desktop.h" +#include "color.h" static void sp_canvastext_class_init (SPCanvasTextClass *klass); static void sp_canvastext_init (SPCanvasText *canvastext); @@ -123,13 +123,11 @@ sp_canvastext_render (SPCanvasItem *item, SPCanvasBuf *buf) cairo_set_font_size(buf->ct, cl->fontsize); cairo_text_path(buf->ct, cl->text); - cairo_set_source_rgba(buf->ct, SP_RGBA32_B_F(cl->rgba_stroke), SP_RGBA32_G_F(cl->rgba_stroke), SP_RGBA32_R_F(cl->rgba_stroke), SP_RGBA32_A_F(cl->rgba_stroke)); + ink_cairo_set_source_rgba32(buf->ct, cl->rgba_stroke); cairo_set_line_width (buf->ct, 2.0); cairo_stroke_preserve(buf->ct); - cairo_set_source_rgba(buf->ct, SP_RGBA32_B_F(cl->rgba), SP_RGBA32_G_F(cl->rgba), SP_RGBA32_R_F(cl->rgba), SP_RGBA32_A_F(cl->rgba)); + ink_cairo_set_source_rgba32(buf->ct, cl->rgba); cairo_fill(buf->ct); - - cairo_new_path(buf->ct); } static void diff --git a/src/display/display-forward.h b/src/display/display-forward.h new file mode 100644 index 000000000..bc7013214 --- /dev/null +++ b/src/display/display-forward.h @@ -0,0 +1,32 @@ +#ifndef SEEN_DISPLAY_DISPLAY_FORWARD_H +#define SEEN_DISPLAY_DISPLAY_FORWARD_H + +#include <glib-object.h> + +struct SPCanvas; +struct SPCanvasClass; +struct SPCanvasItem; +typedef struct _SPCanvasItemClass SPCanvasItemClass; +struct SPCanvasGroup; +struct SPCanvasGroupClass; +class SPCurve; + +namespace Inkscape { +namespace Display { + class TemporaryItem; + class TemporaryItemList; +} +} + +#endif /* !SEEN_DISPLAY_DISPLAY_FORWARD_H */ + +/* + 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 : diff --git a/src/display/grayscale.cpp b/src/display/grayscale.cpp index 37f2b255c..745a08c1e 100644 --- a/src/display/grayscale.cpp +++ b/src/display/grayscale.cpp @@ -21,14 +21,22 @@ namespace Grayscale { +/* Original values from Johan: +const float red_factor = 0.3; +const float green_factor = 0.59; +const float blue_factor = 0.11; +*/ + +// Values below are from the SVG specification +const float red_factor = 0.2125; +const float green_factor = 0.7154; +const float blue_factor = 0.0721; + guint32 process(guint32 rgba) { return process(SP_RGBA32_R_U(rgba), SP_RGBA32_G_U(rgba), SP_RGBA32_B_U(rgba), SP_RGBA32_A_U(rgba)); } guint32 process(guchar r, guchar g, guchar b, guchar a) { - float red_factor = 0.3; - float green_factor = 0.59; - float blue_factor = 0.11; /** To reduce banding in gradients, this calculation is tweaked a bit * by outputing blue+1 or red+1 or both. The luminance is calculated diff --git a/src/display/grayscale.h b/src/display/grayscale.h index d7092687c..fe0d75cad 100644 --- a/src/display/grayscale.h +++ b/src/display/grayscale.h @@ -19,10 +19,6 @@ namespace Grayscale { guint32 process(guchar r, guchar g, guchar b, guchar a); guchar luminance(guchar r, guchar g, guchar b); - const float red_factor = 0.3; - const float green_factor = 0.59; - const float blue_factor = 0.11; - bool activeDesktopIsGrayscale(); }; diff --git a/src/display/guideline.cpp b/src/display/guideline.cpp index abfec250f..c761fa74e 100644 --- a/src/display/guideline.cpp +++ b/src/display/guideline.cpp @@ -13,15 +13,11 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ - -#include <libnr/nr-pixops.h> #include <2geom/transforms.h> #include "sp-canvas-util.h" #include "sp-ctrlpoint.h" #include "guideline.h" -#include "cairo.h" -#include "inkscape-cairo.h" -#include "color.h" +#include "display/cairo-utils.h" static void sp_guideline_class_init(SPGuideLineClass *c); static void sp_guideline_init(SPGuideLine *guideline); @@ -109,74 +105,37 @@ static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf) SPGuideLine const *gl = SP_GUIDELINE (item); - sp_canvas_prepare_buffer(buf); - cairo_t* ctx = nr_create_cairo_context_canvasbuf (NULL /*area*/, buf); //this function ignores the "area" parameter - cairo_set_font_size (ctx, 10); - cairo_set_line_width (ctx, 10); - /// @todo uh??! why must the order of these arguments be reversed? bgra instead of rgba! - cairo_set_source_rgba (ctx, SP_RGBA32_B_F(gl->rgba), SP_RGBA32_G_F(gl->rgba), SP_RGBA32_R_F(gl->rgba), SP_RGBA32_A_F(gl->rgba)); - - unsigned int const r = NR_RGBA32_R (gl->rgba); - unsigned int const g = NR_RGBA32_G (gl->rgba); - unsigned int const b = NR_RGBA32_B (gl->rgba); - unsigned int const a = NR_RGBA32_A (gl->rgba); + cairo_save(buf->ct); + cairo_translate(buf->ct, -buf->rect.x0, -buf->rect.y0); + ink_cairo_set_source_rgba32(buf->ct, gl->rgba); + cairo_set_line_width(buf->ct, 1); + cairo_set_line_cap(buf->ct, CAIRO_LINE_CAP_SQUARE); + cairo_set_font_size(buf->ct, 10); int px = (int) Inkscape::round(gl->point_on_line[Geom::X]); int py = (int) Inkscape::round(gl->point_on_line[Geom::Y]); - if (gl->is_vertical()) { - if (px < buf->rect.x0 || px >= buf->rect.x1) { - return; - } - - int p0 = buf->rect.y0; - int p1 = buf->rect.y1; - int step = buf->buf_rowstride; - unsigned char *d = buf->buf + 4 * (px - buf->rect.x0); - - for (int p = p0; p < p1; p++) { - d[0] = NR_COMPOSEN11_1111(r, a, d[0]); - d[1] = NR_COMPOSEN11_1111(g, a, d[1]); - d[2] = NR_COMPOSEN11_1111(b, a, d[2]); - d += step; - } - - if (gl->label){ - cairo_move_to(ctx, px - buf->rect.x0 + 5, py - buf->rect.y0); - cairo_rotate(ctx, 3.1415/2); - cairo_show_text(ctx, gl->label); - } + if (gl->label) { + cairo_save(buf->ct); + cairo_translate(buf->ct, px, py); + cairo_rotate(buf->ct, atan2(gl->normal_to_line[Geom::X], gl->normal_to_line[Geom::Y])); + cairo_translate(buf->ct, 0, -5); + cairo_move_to(buf->ct, 0, 0); + cairo_show_text(buf->ct, gl->label); + cairo_restore(buf->ct); + } + if (gl->is_vertical()) { + int position = (int) Inkscape::round(gl->point_on_line[Geom::X]); + cairo_move_to(buf->ct, position + 0.5, buf->rect.y0 + 0.5); + cairo_line_to(buf->ct, position + 0.5, buf->rect.y1 - 0.5); + cairo_stroke(buf->ct); } else if (gl->is_horizontal()) { - if (py < buf->rect.y0 || py >= buf->rect.y1) { - return; - } - - int p0 = buf->rect.x0; - int p1 = buf->rect.x1; - int step = 4; - unsigned char *d = buf->buf + (py - buf->rect.y0) * buf->buf_rowstride; - - for (int p = p0; p < p1; p++) { - d[0] = NR_COMPOSEN11_1111(r, a, d[0]); - d[1] = NR_COMPOSEN11_1111(g, a, d[1]); - d[2] = NR_COMPOSEN11_1111(b, a, d[2]); - d += step; - } - - if (gl->label){ - cairo_move_to(ctx, px - buf->rect.x0, py - buf->rect.y0 - 5); - cairo_show_text(ctx, gl->label); - } - + int position = (int) Inkscape::round(gl->point_on_line[Geom::Y]); + cairo_move_to(buf->ct, buf->rect.x0 + 0.5, position + 0.5); + cairo_line_to(buf->ct, buf->rect.x1 - 0.5, position + 0.5); + cairo_stroke(buf->ct); } else { - - if (gl->label){ - cairo_move_to(ctx, px - buf->rect.x0 + 5, py - buf->rect.y0); - cairo_rotate(ctx, atan2(gl->normal_to_line[Geom::X], gl->normal_to_line[Geom::Y])); - cairo_show_text(ctx, gl->label); - } - // render angled line, once intersection has been detected, draw from there. Geom::Point parallel_to_line( gl->normal_to_line[Geom::Y], /*should be minus, but inverted y axis*/ gl->normal_to_line[Geom::X]); @@ -187,7 +146,7 @@ static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf) // intersects with left vertical! double y_intersect_right = (buf->rect.x1 - gl->point_on_line[Geom::X]) * parallel_to_line[Geom::Y] / parallel_to_line[Geom::X] + gl->point_on_line[Geom::Y]; sp_guideline_drawline (buf, buf->rect.x0, static_cast<gint>(round(y_intersect_left)), buf->rect.x1, static_cast<gint>(round(y_intersect_right)), gl->rgba); - return; + goto end; } //try to intersect with right vertical of rect @@ -195,7 +154,7 @@ static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf) if ( (y_intersect_right >= buf->rect.y0) && (y_intersect_right <= buf->rect.y1) ) { // intersects with right vertical! sp_guideline_drawline (buf, buf->rect.x1, static_cast<gint>(round(y_intersect_right)), buf->rect.x0, static_cast<gint>(round(y_intersect_left)), gl->rgba); - return; + goto end; } //try to intersect with top horizontal of rect @@ -204,7 +163,7 @@ static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf) // intersects with top horizontal! double x_intersect_bottom = (buf->rect.y1 - gl->point_on_line[Geom::Y]) * parallel_to_line[Geom::X] / parallel_to_line[Geom::Y] + gl->point_on_line[Geom::X]; sp_guideline_drawline (buf, static_cast<gint>(round(x_intersect_top)), buf->rect.y0, static_cast<gint>(round(x_intersect_bottom)), buf->rect.y1, gl->rgba); - return; + goto end; } //try to intersect with bottom horizontal of rect @@ -212,9 +171,11 @@ static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf) if ( (x_intersect_top >= buf->rect.x0) && (x_intersect_top <= buf->rect.x1) ) { // intersects with bottom horizontal! sp_guideline_drawline (buf, static_cast<gint>(round(x_intersect_bottom)), buf->rect.y1, static_cast<gint>(round(x_intersect_top)), buf->rect.y0, gl->rgba); - return; + goto end; } } + end: + cairo_restore(buf->ct); } static void sp_guideline_update(SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags) @@ -247,7 +208,7 @@ static double sp_guideline_point(SPCanvasItem *item, Geom::Point p, SPCanvasItem SPGuideLine *gl = SP_GUIDELINE (item); if (!gl->sensitive) { - return NR_HUGE; + return Geom::infinity(); } *actual_item = item; @@ -320,82 +281,12 @@ void sp_guideline_delete(SPGuideLine *gl) gtk_object_destroy(GTK_OBJECT(gl)); } -//########################################################## -// Line rendering -#define SAFE_SETPIXEL //undefine this when it is certain that setpixel is never called with invalid params - -/** - \brief This function renders a pixel on a particular buffer. - - The topleft of the buffer equals - ( rect.x0 , rect.y0 ) in screen coordinates - ( 0 , 0 ) in setpixel coordinates - The bottomright of the buffer equals - ( rect.x1 , rect,y1 ) in screen coordinates - ( rect.x1 - rect.x0 , rect.y1 - rect.y0 ) in setpixel coordinates -*/ static void -sp_guideline_setpixel (SPCanvasBuf *buf, gint x, gint y, guint32 rgba) +sp_guideline_drawline (SPCanvasBuf *buf, gint x0, gint y0, gint x1, gint y1, guint32 /*rgba*/) { -#ifdef SAFE_SETPIXEL - if ( (x >= buf->rect.x0) && (x < buf->rect.x1) && (y >= buf->rect.y0) && (y < buf->rect.y1) ) { -#endif - guint r, g, b, a; - r = NR_RGBA32_R (rgba); - g = NR_RGBA32_G (rgba); - b = NR_RGBA32_B (rgba); - a = NR_RGBA32_A (rgba); - guchar * p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x - buf->rect.x0) * 4; - p[0] = NR_COMPOSEN11_1111 (r, a, p[0]); - p[1] = NR_COMPOSEN11_1111 (g, a, p[1]); - p[2] = NR_COMPOSEN11_1111 (b, a, p[2]); -#ifdef SAFE_SETPIXEL - } -#endif -} - -/** - \brief This function renders a line on a particular canvas buffer, - using Bresenham's line drawing function. - http://www.cs.unc.edu/~mcmillan/comp136/Lecture6/Lines.html - Coordinates are interpreted as SCREENcoordinates -*/ -static void -sp_guideline_drawline (SPCanvasBuf *buf, gint x0, gint y0, gint x1, gint y1, guint32 rgba) -{ - int dy = y1 - y0; - int dx = x1 - x0; - int stepx, stepy; - - if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; } - if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; } - dy <<= 1; // dy is now 2*dy - dx <<= 1; // dx is now 2*dx - - sp_guideline_setpixel(buf, x0, y0, rgba); - if (dx > dy) { - int fraction = dy - (dx >> 1); // same as 2*dy - dx - while (x0 != x1) { - if (fraction >= 0) { - y0 += stepy; - fraction -= dx; // same as fraction -= 2*dx - } - x0 += stepx; - fraction += dy; // same as fraction -= 2*dy - sp_guideline_setpixel(buf, x0, y0, rgba); - } - } else { - int fraction = dx - (dy >> 1); - while (y0 != y1) { - if (fraction >= 0) { - x0 += stepx; - fraction -= dy; - } - y0 += stepy; - fraction += dx; - sp_guideline_setpixel(buf, x0, y0, rgba); - } - } + cairo_move_to(buf->ct, x0 + 0.5, y0 + 0.5); + cairo_line_to(buf->ct, x1 + 0.5, y1 + 0.5); + cairo_stroke(buf->ct); } /* diff --git a/src/display/inkscape-cairo.cpp b/src/display/inkscape-cairo.cpp deleted file mode 100644 index 4fc492ba8..000000000 --- a/src/display/inkscape-cairo.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Helper functions to use cairo with inkscape - * - * Copyright (C) 2007 bulia byak - * Copyright (C) 2008 Johan Engelen - * - * Released under GNU GPL - * - */ - -#include <cairo.h> - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <libnr/nr-pixblock.h> -#include <libnr/nr-convert2geom.h> -#include "../style.h" -#include "nr-arena.h" -#include "sp-canvas.h" -#include <2geom/pathvector.h> -#include <2geom/bezier-curve.h> -#include <2geom/hvlinesegment.h> -#include <2geom/affine.h> -#include <2geom/point.h> -#include <2geom/path.h> -#include <2geom/transforms.h> -#include <2geom/sbasis-to-bezier.h> -#include "helper/geom-curves.h" - -/** Creates a cairo context to render to the given pixblock on the given area */ -cairo_t * -nr_create_cairo_context_for_data (NRRectL *area, NRRectL *buf_area, unsigned char *px, unsigned int rowstride) -{ - if (!nr_rect_l_test_intersect_ptr(buf_area, area)) - return NULL; - - NRRectL clip; - nr_rect_l_intersect (&clip, buf_area, area); - unsigned char *dpx = px + (clip.y0 - buf_area->y0) * rowstride + 4 * (clip.x0 - buf_area->x0); - int width = area->x1 - area->x0; - int height = area->y1 - area->y0; - // even though cairo cannot draw in nonpremul mode, select ARGB32 for R8G8B8A8N as the closest; later eliminate R8G8B8A8N everywhere - cairo_surface_t* cst = cairo_image_surface_create_for_data - (dpx, - CAIRO_FORMAT_ARGB32, - width, - height, - rowstride); - cairo_t *ct = cairo_create (cst); - - return ct; -} - -/** Creates a cairo context to render to the given SPCanvasBuf on the given area */ -cairo_t * -nr_create_cairo_context_canvasbuf (NRRectL */*area*/, SPCanvasBuf *b) -{ - return nr_create_cairo_context_for_data (&(b->rect), &(b->rect), b->buf, b->buf_rowstride); -} - - -/** Creates a cairo context to render to the given NRPixBlock on the given area */ -cairo_t * -nr_create_cairo_context (NRRectL *area, NRPixBlock *pb) -{ - return nr_create_cairo_context_for_data (area, &(pb->area), NR_PIXBLOCK_PX (pb), pb->rs); -} - -/* - * Can be called recursively. - * If optimize_stroke == false, the view Rect is not used. - */ -static void -feed_curve_to_cairo(cairo_t *cr, Geom::Curve const &c, Geom::Affine const & trans, Geom::Rect view, bool optimize_stroke) -{ - if( is_straight_curve(c) ) - { - Geom::Point end_tr = c.finalPoint() * trans; - if (!optimize_stroke) { - cairo_line_to(cr, end_tr[0], end_tr[1]); - } else { - Geom::Rect swept(c.initialPoint()*trans, end_tr); - if (swept.intersects(view)) { - cairo_line_to(cr, end_tr[0], end_tr[1]); - } else { - cairo_move_to(cr, end_tr[0], end_tr[1]); - } - } - } - else if(Geom::QuadraticBezier const *quadratic_bezier = dynamic_cast<Geom::QuadraticBezier const*>(&c)) { - std::vector<Geom::Point> points = quadratic_bezier->points(); - points[0] *= trans; - points[1] *= trans; - points[2] *= trans; - Geom::Point b1 = points[0] + (2./3) * (points[1] - points[0]); - Geom::Point b2 = b1 + (1./3) * (points[2] - points[0]); - if (!optimize_stroke) { - cairo_curve_to(cr, b1[0], b1[1], b2[0], b2[1], points[2][0], points[2][1]); - } else { - Geom::Rect swept(points[0], points[2]); - swept.expandTo(points[1]); - if (swept.intersects(view)) { - cairo_curve_to(cr, b1[0], b1[1], b2[0], b2[1], points[2][0], points[2][1]); - } else { - cairo_move_to(cr, points[2][0], points[2][1]); - } - } - } - else if(Geom::CubicBezier const *cubic_bezier = dynamic_cast<Geom::CubicBezier const*>(&c)) { - std::vector<Geom::Point> points = cubic_bezier->points(); - //points[0] *= trans; // don't do this one here for fun: it is only needed for optimized strokes - points[1] *= trans; - points[2] *= trans; - points[3] *= trans; - if (!optimize_stroke) { - cairo_curve_to(cr, points[1][0], points[1][1], points[2][0], points[2][1], points[3][0], points[3][1]); - } else { - points[0] *= trans; // didn't transform this point yet - Geom::Rect swept(points[0], points[3]); - swept.expandTo(points[1]); - swept.expandTo(points[2]); - if (swept.intersects(view)) { - cairo_curve_to(cr, points[1][0], points[1][1], points[2][0], points[2][1], points[3][0], points[3][1]); - } else { - cairo_move_to(cr, points[3][0], points[3][1]); - } - } - } -// else if(Geom::SVGEllipticalArc const *svg_elliptical_arc = dynamic_cast<Geom::SVGEllipticalArc *>(c)) { -// //TODO: get at the innards and spit them out to cairo -// } - else { - //this case handles sbasis as well as all other curve types - Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(c.toSBasis(), 0.1); - - //recurse to convert the new path resulting from the sbasis to svgd - for(Geom::Path::iterator iter = sbasis_path.begin(); iter != sbasis_path.end(); ++iter) { - feed_curve_to_cairo(cr, *iter, trans, view, optimize_stroke); - } - } -} - - -/** Feeds path-creating calls to the cairo context translating them from the Path */ -static void -feed_path_to_cairo (cairo_t *ct, Geom::Path const &path) -{ - if (path.empty()) - return; - - cairo_move_to(ct, path.initialPoint()[0], path.initialPoint()[1] ); - - for(Geom::Path::const_iterator cit = path.begin(); cit != path.end_open(); ++cit) { - feed_curve_to_cairo(ct, *cit, Geom::identity(), Geom::Rect(), false); // optimize_stroke is false, so the view rect is not used - } - - if (path.closed()) { - cairo_close_path(ct); - } -} - -/** Feeds path-creating calls to the cairo context translating them from the Path, with the given transform and shift */ -static void -feed_path_to_cairo (cairo_t *ct, Geom::Path const &path, Geom::Affine trans, Geom::OptRect area, bool optimize_stroke, double stroke_width) -{ - if (!area) - return; - if (path.empty()) - return; - - // Transform all coordinates to coords within "area" - Geom::Point shift = area->min(); - Geom::Rect view = *area; - view.expandBy (stroke_width); - view = view * (Geom::Affine)Geom::Translate(-shift); - // Pass transformation to feed_curve, so that we don't need to create a whole new path. - Geom::Affine transshift(trans * Geom::Translate(-shift)); - - Geom::Point initial = path.initialPoint() * transshift; - cairo_move_to(ct, initial[0], initial[1] ); - - for(Geom::Path::const_iterator cit = path.begin(); cit != path.end_open(); ++cit) { - feed_curve_to_cairo(ct, *cit, transshift, view, optimize_stroke); - } - - if (path.closed()) { - if (!optimize_stroke) { - cairo_close_path(ct); - } else { - cairo_line_to(ct, initial[0], initial[1]); - /* We cannot use cairo_close_path(ct) here because some parts of the path may have been - clipped and not drawn (maybe the before last segment was outside view area), which - would result in closing the "subpath" after the last interruption, not the entire path. - - However, according to cairo documentation: - The behavior of cairo_close_path() is distinct from simply calling cairo_line_to() with the equivalent coordinate - in the case of stroking. When a closed sub-path is stroked, there are no caps on the ends of the sub-path. Instead, - there is a line join connecting the final and initial segments of the sub-path. - - The correct fix will be possible when cairo introduces methods for moving without - ending/starting subpaths, which we will use for skipping invisible segments; then we - will be able to use cairo_close_path here. This issue also affects ps/eps/pdf export, - see bug 168129 - */ - } - } -} - -/** Feeds path-creating calls to the cairo context translating them from the PathVector, with the given transform and shift - * One must have done cairo_new_path(ct); before calling this function. */ -void -feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv, Geom::Affine trans, Geom::OptRect area, bool optimize_stroke, double stroke_width) -{ - if (!area) - return; - if (pathv.empty()) - return; - - for(Geom::PathVector::const_iterator it = pathv.begin(); it != pathv.end(); ++it) { - feed_path_to_cairo(ct, *it, trans, area, optimize_stroke, stroke_width); - } -} - -/** Feeds path-creating calls to the cairo context translating them from the PathVector - * One must have done cairo_new_path(ct); before calling this function. */ -void -feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv) -{ - if (pathv.empty()) - return; - - for(Geom::PathVector::const_iterator it = pathv.begin(); it != pathv.end(); ++it) { - feed_path_to_cairo(ct, *it); - } -} - -/* - 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 : diff --git a/src/display/inkscape-cairo.h b/src/display/inkscape-cairo.h deleted file mode 100644 index 4133661fe..000000000 --- a/src/display/inkscape-cairo.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __INKSCAPE_CAIRO_H__ -#define __INKSCAPE_CAIRO_H__ - -/* - * Helper functions to use cairo with inkscape - * - * Copyright (C) 2007 bulia byak - * Copyright (C) 2008 Johan Engelen - * - * Released under GNU GPL - * - */ - -#include <2geom/forward.h> -#include <cairo/cairo.h> -#include <boost/optional.hpp> -#include "libnr/nr-rect.h" - -struct NRPixBlock; -class SPCanvasBuf; - -cairo_t *nr_create_cairo_context_canvasbuf (NRRectL *area, SPCanvasBuf *b); -cairo_t *nr_create_cairo_context (NRRectL *area, NRPixBlock *pb); -void feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv, Geom::Affine trans, Geom::OptRect area, bool optimize_stroke, double stroke_width); -void feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv); - -#endif -/* - 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 : diff --git a/src/display/nr-3dutils.cpp b/src/display/nr-3dutils.cpp index c5e7b4c1b..eb6858374 100644 --- a/src/display/nr-3dutils.cpp +++ b/src/display/nr-3dutils.cpp @@ -11,134 +11,15 @@ #include <glib/gmessages.h> -#include "libnr/nr-pixblock.h" #include "display/nr-3dutils.h" #include <cmath> +#include <2geom/point.h> +#include <2geom/affine.h> namespace NR { -#define BEGIN 0 // TOP or LEFT -#define MIDDLE 1 -#define END 2 // BOTTOM or RIGHT - -#define START(v) ((v)==BEGIN? 1 : 0) -#define FINISH(v) ((v)==END? 1 : 2) - -signed char K_X[3][3][3][3] = { - //K_X[TOP] - { - //K_X[TOP][LEFT] - { - { 0, 0, 0}, - { 0, -2, 2}, - { 0, -1, 1} - }, - { - { 0, 0, 0}, - {-2, 0, 2}, - {-1, 0, 1} - }, - { - { 0, 0, 0}, - {-2, 2, 0}, - {-1, 1, 0} - } - }, - //K_X[MIDDLE] - { - //K_X[MIDDLE][LEFT] - { - { 0, -1, 1}, - { 0, -2, 2}, - { 0, -1, 1} - }, - { - {-1, 0, 1}, - {-2, 0, 2}, - {-1, 0, 1} - }, - { - {-1, 1, 0}, - {-2, 2, 0}, - {-1, 1, 0} - } - }, - //K_X[BOTTOM] - { - //K_X[BOTTOM][LEFT] - { - { 0, -1, 1}, - { 0, -2, 2}, - { 0, 0, 0} - }, - { - {-1, 0, 1}, - {-2, 0, 2}, - { 0, 0, 0} - }, - { - {-1, 1, 0}, - {-2, 2, 0}, - { 0, 0, 0} - } - } -}; - -//K_Y is obtained by transposing K_X globally and each of its components - -gdouble FACTOR_X[3][3] = { - {2./3, 1./3, 2./3}, - {1./2, 1./4, 1./2}, - {2./3, 1./3, 2./3} -}; - -//FACTOR_Y is obtained by transposing FACTOR_X - -inline -int get_carac(int i, int len, int delta) { - if (i < delta) - return BEGIN; - else if (i > len - 1 - delta) - return END; - else - return MIDDLE; -} - -//assumes in is RGBA -//should be made more resistant -void compute_surface_normal(Fvector &N, gdouble ss, NRPixBlock *in, int i, int j, int dx, int dy) { - int w = in->area.x1 - in->area.x0; - int h = in->area.y1 - in->area.y0; - int k, l, alpha_idx, alpha_idx_y; - int x_carac, y_carac; - gdouble alpha; - gdouble accu_x; - gdouble accu_y; - unsigned char *data = NR_PIXBLOCK_PX (in); - g_assert(NR_PIXBLOCK_BPP(in) == 4); - x_carac = get_carac(j, w, dx); //LEFT, MIDDLE or RIGHT - y_carac = get_carac(i, h, dy); //TOP, MIDDLE or BOTTOM - alpha_idx = 4*(i*w + j); - accu_x = 0; - accu_y = 0; - for (k = START(y_carac); k <= FINISH(y_carac); k++) { - alpha_idx_y = alpha_idx + 4*(k-1)*dy*w; - for (l = START(x_carac); l <= FINISH(x_carac); l++) { - alpha = (data + alpha_idx_y + 4*dx*(l-1))[3]; - accu_x += K_X[y_carac][x_carac][k][l] * alpha; - accu_y += K_X[x_carac][y_carac][l][k] * alpha; - } - } - ss /= 255.0; // Correction for scale of pixel values - N[X_3D] = -ss * FACTOR_X[y_carac][x_carac] * accu_x / dx; - N[Y_3D] = -ss * FACTOR_X[x_carac][y_carac] * accu_y / dy; - N[Z_3D] = 1.0; - normalize_vector(N); - //std::cout << "(" << N[X_3D] << ", " << N[Y_3D] << ", " << N[Z_3D] << ")" << std::endl; -} - void convert_coord(gdouble &x, gdouble &y, gdouble &z, Geom::Affine const &trans) { - Point p = Point(x, y); + Geom::Point p = Geom::Point(x, y); p *= trans; x = p[Geom::X]; y = p[Geom::Y]; diff --git a/src/display/nr-3dutils.h b/src/display/nr-3dutils.h index e19651ac8..44cb371e6 100644 --- a/src/display/nr-3dutils.h +++ b/src/display/nr-3dutils.h @@ -28,12 +28,24 @@ namespace NR { /** * a type of 3 gdouble components vectors */ -typedef gdouble Fvector[3]; +struct Fvector { + Fvector() { + v[0] = v[1] = v[2] = 0.0; + } + Fvector(double x, double y, double z) { + v[0] = x; + v[1] = y; + v[2] = z; + } + double v[3]; + double &operator[](unsigned i) { return v[i]; } + double operator[](unsigned i) const { return v[i]; } +}; /** * The eye vector */ -const static Fvector EYE_VECTOR = {0, 0, 1}; +const static Fvector EYE_VECTOR(0, 0, 1); /** * returns the euclidian norm of the vector v @@ -69,22 +81,6 @@ gdouble scalar_product(const Fvector &a, const Fvector &b); void normalized_sum(Fvector &r, const Fvector &a, const Fvector &b); /** - * Computes the unit suface normal vector of surface given by "in" at (i, j) - * and store it into N. "in" is a (NRPixBlock *) in mode RGBA but only the alpha - * channel is considered as a bump map. ss is the altitude when for the alpha - * value 255. dx and dy are the deltas used to compute in our discrete setting - * - * \param N a reference to a Fvector in which we store the unit surface normal - * \param ss the surface scale - * \param in a NRPixBlock * whose alpha channel codes the surface - * \param i the x coordinate of the point at which we compute the normal - * \param j the y coordinate of the point at which we compute the normal - * \param dx the delta used in the x coordinate - * \param dy the delta used in the y coordinate - */ -void compute_surface_normal(Fvector &N, gdouble ss, NRPixBlock *in, int i, int j, int dx, int dy); - -/** * Applies the transformation matrix to (x, y, z). This function assumes that * trans[0] = trans[3]. x and y are transformed according to trans, z is * multiplied by trans[0]. diff --git a/src/display/nr-arena-glyphs.cpp b/src/display/nr-arena-glyphs.cpp index a67812d8f..facb5e9c6 100644 --- a/src/display/nr-arena-glyphs.cpp +++ b/src/display/nr-arena-glyphs.cpp @@ -1,5 +1,3 @@ -#define __NR_ARENA_GLYPHS_C__ - /* * RGBA display list system for inkscape * @@ -16,22 +14,18 @@ #ifdef HAVE_CONFIG_H # include <config.h> #endif -#include <libnr/nr-blit.h> -#include <libnr/nr-convert2geom.h> +#include "libnr/nr-convert2geom.h" #include <2geom/affine.h> -#include "../style.h" -#include "nr-arena.h" -#include "nr-arena-glyphs.h" +#include "style.h" +#include "display/nr-arena.h" +#include "display/nr-arena-glyphs.h" #include <cairo.h> -#include "inkscape-cairo.h" -#include "display/grayscale.h" -#include "sp-paint-server.h" +#include "display/cairo-utils.h" +#include "helper/geom.h" #ifdef test_glyph_liv #include "../display/canvas-bpath.h" -#include <libnrtype/font-instance.h> -#include <libnrtype/raster-glyph.h> -#include <libnrtype/RasterFont.h> +#include "libnrtype/font-instance.h" // defined in nr-arena-shape.cpp void nr_pixblock_render_shape_mask_or(NRPixBlock &m, Shape *theS); @@ -46,7 +40,7 @@ static void nr_arena_glyphs_init(NRArenaGlyphs *glyphs); static void nr_arena_glyphs_finalize(NRObject *object); static guint nr_arena_glyphs_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset); -static guint nr_arena_glyphs_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb); +static guint nr_arena_glyphs_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area); static NRArenaItem *nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); static NRArenaItemClass *glyphs_parent_class; @@ -88,13 +82,9 @@ nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass) static void nr_arena_glyphs_init(NRArenaGlyphs *glyphs) { - glyphs->style = NULL; glyphs->g_transform.setIdentity(); glyphs->font = NULL; glyphs->glyph = 0; - - glyphs->rfont = NULL; - glyphs->sfont = NULL; glyphs->x = glyphs->y = 0.0; } @@ -103,132 +93,70 @@ nr_arena_glyphs_finalize(NRObject *object) { NRArenaGlyphs *glyphs = static_cast<NRArenaGlyphs *>(object); - if (glyphs->rfont) { - glyphs->rfont->Unref(); - glyphs->rfont=NULL; - } - if (glyphs->sfont) { - glyphs->sfont->Unref(); - glyphs->sfont=NULL; - } - if (glyphs->font) { glyphs->font->Unref(); glyphs->font=NULL; } - if (glyphs->style) { - sp_style_unref(glyphs->style); - glyphs->style = NULL; - } - ((NRObjectClass *) glyphs_parent_class)->finalize(object); } static guint nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*area*/, NRGC *gc, guint /*state*/, guint /*reset*/) { - NRArenaGlyphs *glyphs; - raster_font *rfont; - - glyphs = NR_ARENA_GLYPHS(item); + NRArenaGlyphs *glyphs = NR_ARENA_GLYPHS(item); + NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item->parent); - if (!glyphs->font || !glyphs->style) + if (!glyphs->font || !ggroup->style) return NR_ARENA_ITEM_STATE_ALL; - if ((glyphs->style->fill.isNone()) && (glyphs->style->stroke.isNone())) + if (ggroup->nrstyle.fill.type == NRStyle::PAINT_NONE && ggroup->nrstyle.stroke.type == NRStyle::PAINT_NONE) return NR_ARENA_ITEM_STATE_ALL; - NRRect bbox; - bbox.x0 = bbox.y0 = NR_HUGE; - bbox.x1 = bbox.y1 = -NR_HUGE; - - float const scale = gc->transform.descrim(); - - if (!glyphs->style->fill.isNone()) { - Geom::Affine t; - t = glyphs->g_transform * gc->transform; - glyphs->x = t[4]; - glyphs->y = t[5]; - t[4]=0; - t[5]=0; - rfont = glyphs->font->RasterFont(t, 0); - if (glyphs->rfont) glyphs->rfont->Unref(); - glyphs->rfont = rfont; - - if (glyphs->style->stroke.isNone() || fabs(glyphs->style->stroke_width.computed * scale) <= 0.01) { // Optimization: do fill bbox only if there's no stroke - NRRect narea; - if ( glyphs->rfont ) glyphs->rfont->BBox(glyphs->glyph, &narea); - bbox.x0 = narea.x0 + glyphs->x; - bbox.y0 = narea.y0 + glyphs->y; - bbox.x1 = narea.x1 + glyphs->x; - bbox.y1 = narea.y1 + glyphs->y; + Geom::OptRect b; + Geom::Affine t = glyphs->g_transform * gc->transform; + glyphs->x = t[4]; + glyphs->y = t[5]; + + b = bounds_exact_transformed(*glyphs->font->PathVector(glyphs->glyph), t); + if (b && ggroup->nrstyle.stroke.type != NRStyle::PAINT_NONE) { + float width, scale; + scale = gc->transform.descrim(); + width = MAX(0.125, ggroup->nrstyle.stroke_width * scale); + if ( fabs(ggroup->nrstyle.stroke_width * scale) > 0.01 ) { // FIXME: this is always true + b->expandBy(width); } - } - - if (!glyphs->style->stroke.isNone()) { - /* Build state data */ - Geom::Affine t; - t = glyphs->g_transform * gc->transform; - glyphs->x = t[4]; - glyphs->y = t[5]; - t[4]=0; - t[5]=0; - - if ( fabs(glyphs->style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord - font_style nstyl; - nstyl.transform = t; - nstyl.stroke_width=MAX(0.125, glyphs->style->stroke_width.computed * scale); - if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_BUTT ) nstyl.stroke_cap=butt_straight; - if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_ROUND ) nstyl.stroke_cap=butt_round; - if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_SQUARE ) nstyl.stroke_cap=butt_square; - if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_MITER ) nstyl.stroke_join=join_pointy; - if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_ROUND ) nstyl.stroke_join=join_round; - if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_BEVEL ) nstyl.stroke_join=join_straight; - nstyl.stroke_miter_limit = glyphs->style->stroke_miterlimit.value; - nstyl.nbDash=0; - nstyl.dash_offset = 0; - nstyl.dashes=NULL; - if ( glyphs->style->stroke_dash.n_dash > 0 ) { - nstyl.dash_offset = glyphs->style->stroke_dash.offset * scale; - nstyl.nbDash=glyphs->style->stroke_dash.n_dash; - nstyl.dashes=(double*)malloc(nstyl.nbDash*sizeof(double)); - for (int i = 0; i < nstyl.nbDash; i++) nstyl.dashes[i]= glyphs->style->stroke_dash.dash[i] * scale; - } - rfont = glyphs->font->RasterFont( nstyl); - if ( nstyl.dashes ) free(nstyl.dashes); - if (glyphs->sfont) glyphs->sfont->Unref(); - glyphs->sfont = rfont; - - NRRect narea; - if ( glyphs->sfont ) glyphs->sfont->BBox(glyphs->glyph, &narea); - narea.x0-=nstyl.stroke_width; - narea.y0-=nstyl.stroke_width; - narea.x1+=nstyl.stroke_width; - narea.y1+=nstyl.stroke_width; - bbox.x0 = narea.x0 + glyphs->x; - bbox.y0 = narea.y0 + glyphs->y; - bbox.x1 = narea.x1 + glyphs->x; - bbox.y1 = narea.y1 + glyphs->y; + // those pesky miters, now + float miterMax = width * ggroup->nrstyle.miter_limit; + if ( miterMax > 0.01 ) { + // grunt mode. we should compute the various miters instead + // (one for each point on the curve) + b->expandBy(miterMax); } } - if (nr_rect_d_test_empty(bbox)) return NR_ARENA_ITEM_STATE_ALL; - item->bbox.x0 = static_cast<NR::ICoord>(floor(bbox.x0)); - item->bbox.y0 = static_cast<NR::ICoord>(floor(bbox.y0)); - item->bbox.x1 = static_cast<NR::ICoord>(ceil (bbox.x1)); - item->bbox.y1 = static_cast<NR::ICoord>(ceil (bbox.y1)); + if (b) { + item->bbox.x0 = static_cast<NR::ICoord>(floor(b->left())); + item->bbox.y0 = static_cast<NR::ICoord>(floor(b->top())); + item->bbox.x1 = static_cast<NR::ICoord>(ceil (b->right())); + item->bbox.y1 = static_cast<NR::ICoord>(ceil (b->bottom())); + } else { + item->bbox.x0 = 0; + item->bbox.y0 = 0; + item->bbox.x1 = -1; + item->bbox.y1 = -1; + } return NR_ARENA_ITEM_STATE_ALL; } static guint -nr_arena_glyphs_clip(NRArenaItem *item, NRRectL */*area*/, NRPixBlock */*pb*/) +nr_arena_glyphs_clip(cairo_t *ct, NRArenaItem *item, NRRectL */*area*/) { NRArenaGlyphs *glyphs; glyphs = NR_ARENA_GLYPHS(item); - if (!glyphs->font ) return item->state; + if (!glyphs->font) return item->state; /* TODO : render to greyscale pixblock provided for clipping */ @@ -243,7 +171,6 @@ nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned i glyphs = NR_ARENA_GLYPHS(item); if (!glyphs->font ) return NULL; - if (!glyphs->style) return NULL; double const x = p[Geom::X]; double const y = p[Geom::Y]; @@ -275,53 +202,13 @@ nr_arena_glyphs_set_path(NRArenaGlyphs *glyphs, SPCurve */*curve*/, unsigned int nr_arena_item_request_update(NR_ARENA_ITEM(glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE); } -void -nr_arena_glyphs_set_style(NRArenaGlyphs *glyphs, SPStyle *style) -{ - nr_return_if_fail(glyphs != NULL); - nr_return_if_fail(NR_IS_ARENA_GLYPHS(glyphs)); - - if (style) sp_style_ref(style); - if (glyphs->style) sp_style_unref(glyphs->style); - glyphs->style = style; - - nr_arena_item_request_update(NR_ARENA_ITEM(glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -static guint -nr_arena_glyphs_fill_mask(NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m) -{ - /* fixme: area == m->area, so merge these */ - - NRArenaItem *item = NR_ARENA_ITEM(glyphs); - - if (glyphs->rfont && nr_rect_l_test_intersect_ptr(area, &item->bbox)) { - raster_glyph *g = glyphs->rfont->GetGlyph(glyphs->glyph); - if ( g ) g->Blit(Geom::Point(glyphs->x, glyphs->y), *m); - } - - return item->state; -} - -static guint -nr_arena_glyphs_stroke_mask(NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m) -{ - NRArenaItem *item = NR_ARENA_ITEM(glyphs); - if (glyphs->sfont && nr_rect_l_test_intersect_ptr(area, &item->bbox)) { - raster_glyph *g=glyphs->sfont->GetGlyph(glyphs->glyph); - if ( g ) g->Blit(Geom::Point(glyphs->x, glyphs->y),*m); - } - - return item->state; -} - static void nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass); static void nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group); static void nr_arena_glyphs_group_finalize(NRObject *object); static guint nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset); static unsigned int nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags); -static unsigned int nr_arena_glyphs_group_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb); +static unsigned int nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area); static NRArenaItem *nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned int sticky); static NRArenaGroupClass *group_parent_class; @@ -366,10 +253,7 @@ nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group) { group->style = NULL; group->paintbox.x0 = group->paintbox.y0 = 0.0F; - group->paintbox.x1 = group->paintbox.y1 = 1.0F; - - group->fill_painter = NULL; - group->stroke_painter = NULL; + group->paintbox.x1 = group->paintbox.y1 = -1.0F; } static void @@ -377,16 +261,6 @@ nr_arena_glyphs_group_finalize(NRObject *object) { NRArenaGlyphsGroup *group=static_cast<NRArenaGlyphsGroup *>(object); - if (group->fill_painter) { - sp_painter_free(group->fill_painter); - group->fill_painter = NULL; - } - - if (group->stroke_painter) { - sp_painter_free(group->stroke_painter); - group->stroke_painter = NULL; - } - if (group->style) { sp_style_unref(group->style); group->style = NULL; @@ -400,34 +274,7 @@ nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint s { NRArenaGlyphsGroup *group = NR_ARENA_GLYPHS_GROUP(item); - if (group->fill_painter) { - sp_painter_free(group->fill_painter); - group->fill_painter = NULL; - } - - if (group->stroke_painter) { - sp_painter_free(group->stroke_painter); - group->stroke_painter = NULL; - } - - item->render_opacity = TRUE; - if (group->style->fill.isPaintserver()) { - group->fill_painter = sp_paint_server_painter_new(SP_STYLE_FILL_SERVER(group->style), - gc->transform, gc->parent->transform, - &group->paintbox); - item->render_opacity = FALSE; - } - - if (group->style->stroke.isPaintserver()) { - group->stroke_painter = sp_paint_server_painter_new(SP_STYLE_STROKE_SERVER(group->style), - gc->transform, gc->parent->transform, - &group->paintbox); - item->render_opacity = FALSE; - } - - if ( item->render_opacity == TRUE && !group->style->stroke.isNone() && !group->style->fill.isNone() ) { - item->render_opacity=FALSE; - } + group->nrstyle.update(); if (((NRArenaItemClass *) group_parent_class)->update) return ((NRArenaItemClass *) group_parent_class)->update(item, area, gc, state, reset); @@ -443,155 +290,81 @@ nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPi NRArenaGroup *group = NR_ARENA_GROUP(item); NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item); - SPStyle const *style = ggroup->style; - guint ret = item->state; - bool print_colors_preview = (item->arena->colorrendermode == Inkscape::COLORRENDERMODE_PRINT_COLORS_PREVIEW); - bool grayscale = (item->arena->colorrendermode == Inkscape::COLORRENDERMODE_GRAYSCALE); + if (!ct) return item->state; if (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) { - if (!ct) - return item->state; - guint32 rgba = item->arena->outlinecolor; - // FIXME: we use RGBA buffers but cairo writes BGRA (on i386), so we must cheat - // by setting color channels in the "wrong" order - cairo_set_source_rgba(ct, SP_RGBA32_B_F(rgba), SP_RGBA32_G_F(rgba), SP_RGBA32_R_F(rgba), SP_RGBA32_A_F(rgba)); + ink_cairo_set_source_rgba32(ct, rgba); cairo_set_tolerance(ct, 1.25); // low quality, but good enough for outline mode + NRRect temp(area->x0, area->y0, area->x1, area->y1); + Geom::OptRect area_2geom = temp.upgrade_2geom(); + for (child = group->children; child != NULL; child = child->next) { NRArenaGlyphs *g = NR_ARENA_GLYPHS(child); Geom::PathVector const * pathv = g->font->PathVector(g->glyph); + Geom::Affine transform = g->g_transform * group->ctm; cairo_new_path(ct); - Geom::Affine transform = g->g_transform * group->ctm; - feed_pathvector_to_cairo (ct, *pathv, transform, to_2geom((pb->area).upgrade()), false, 0); + ink_cairo_transform(ct, transform); + feed_pathvector_to_cairo (ct, *pathv); cairo_fill(ct); - pb->empty = FALSE; } - return ret; + return item->state; } + // NOTE: this is very similar to nr-arena-shape.cpp; the only difference is path feeding + bool has_stroke, has_fill; + cairo_save(ct); + ink_cairo_transform(ct, ggroup->ctm); - /* Fill */ - if (!style->fill.isNone() || item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) { - NRPixBlock m; - nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE); - - // if memory allocation failed, abort - if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) { - nr_pixblock_release (&m); - return (item->state); - } - - m.visible_area = pb->visible_area; - - /* Render children fill mask */ - for (child = group->children; child != NULL; child = child->next) { - ret = nr_arena_glyphs_fill_mask(NR_ARENA_GLYPHS(child), area, &m); - if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) { - nr_pixblock_release(&m); - return ret; - } - } + has_fill = ggroup->nrstyle.prepareFill(ct, &ggroup->paintbox); + has_stroke = ggroup->nrstyle.prepareStroke(ct, &ggroup->paintbox); - /* Composite into buffer */ - if (style->fill.isPaintserver()) { - if (ggroup->fill_painter) { - nr_arena_render_paintserver_fill(pb, area, ggroup->fill_painter, SP_SCALE24_TO_FLOAT(style->fill_opacity.value), &m); - } - } else if (style->fill.isColor() || item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) { - guint32 rgba; - if (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) { - // In outline mode, render fill only, using outlinecolor - rgba = item->arena->outlinecolor; - } else if ( item->render_opacity ) { - rgba = style->fill.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->fill_opacity.value) * - SP_SCALE24_TO_FLOAT(style->opacity.value) ); - } else { - rgba = style->fill.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->fill_opacity.value) ); - } - - if (print_colors_preview) { - nr_arena_separate_color_plates(&rgba); - } else if (grayscale) { - rgba = Grayscale::process(rgba); - } - - nr_blit_pixblock_mask_rgba32(pb, &m, rgba); - pb->empty = FALSE; - } - - nr_pixblock_release(&m); - } - - /* Stroke */ - if (!style->stroke.isNone() && !(item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE)) { - NRPixBlock m; - guint32 rgba; - nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE); + if (has_fill || has_stroke) { + for (NRArenaItem *child = ggroup->children; child != NULL; child = child->next) { + NRArenaGlyphs *g = NR_ARENA_GLYPHS(child); + Geom::PathVector const &pathv = *g->font->PathVector(g->glyph); - // if memory allocation failed, abort - if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) { - nr_pixblock_release (&m); - return (item->state); + cairo_save(ct); + ink_cairo_transform(ct, g->g_transform); + feed_pathvector_to_cairo(ct, pathv); + cairo_restore(ct); } - m.visible_area = pb->visible_area; - /* Render children stroke mask */ - for (child = group->children; child != NULL; child = child->next) { - ret = nr_arena_glyphs_stroke_mask(NR_ARENA_GLYPHS(child), area, &m); - if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) { - nr_pixblock_release(&m); - return ret; - } + if (has_fill) { + ggroup->nrstyle.applyFill(ct); + cairo_fill_preserve(ct); } - /* Composite into buffer */ - if (style->stroke.isPaintserver()) { - if (ggroup->stroke_painter) { - nr_arena_render_paintserver_fill(pb, area, ggroup->stroke_painter, SP_SCALE24_TO_FLOAT(style->stroke_opacity.value), &m); - } - } else if (style->stroke.isColor()) { - if ( item->render_opacity ) { - rgba = style->stroke.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->stroke_opacity.value) * - SP_SCALE24_TO_FLOAT(style->opacity.value) ); - } else { - rgba = style->stroke.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->stroke_opacity.value) ); - } - - if (print_colors_preview) { - nr_arena_separate_color_plates(&rgba); - } else if (grayscale) { - rgba = Grayscale::process(rgba); - } - - nr_blit_pixblock_mask_rgba32(pb, &m, rgba); - pb->empty = FALSE; - } else { - // nothing + if (has_stroke) { + ggroup->nrstyle.applyStroke(ct); + cairo_stroke_preserve(ct); } - nr_pixblock_release(&m); - } + cairo_new_path(ct); // clear path + } // has fill or stroke pattern + cairo_restore(ct); - return ret; + return item->state; } static unsigned int -nr_arena_glyphs_group_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb) +nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area) { - NRArenaGroup *group = NR_ARENA_GROUP(item); + //NRArenaGroup *group = NR_ARENA_GROUP(item); guint ret = item->state; /* Render children fill mask */ + /* for (NRArenaItem *child = group->children; child != NULL; child = child->next) { ret = nr_arena_glyphs_fill_mask(NR_ARENA_GLYPHS(child), area, pb); if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) return ret; - } + }*/ return ret; } @@ -638,7 +411,6 @@ nr_arena_glyphs_group_add_component(NRArenaGlyphsGroup *sg, font_instance *font, nr_arena_item_append_child(NR_ARENA_ITEM(group), new_arena); nr_arena_item_unref(new_arena); nr_arena_glyphs_set_path(NR_ARENA_GLYPHS(new_arena), NULL, FALSE, font, glyph, &transform); - nr_arena_glyphs_set_style(NR_ARENA_GLYPHS(new_arena), sg->style); } } @@ -648,16 +420,11 @@ nr_arena_glyphs_group_set_style(NRArenaGlyphsGroup *sg, SPStyle *style) nr_return_if_fail(sg != NULL); nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(sg)); - NRArenaGroup *group = NR_ARENA_GROUP(sg); - if (style) sp_style_ref(style); if (sg->style) sp_style_unref(sg->style); sg->style = style; - for (NRArenaItem *child = group->children; child != NULL; child = child->next) { - nr_return_if_fail(NR_IS_ARENA_GLYPHS(child)); - nr_arena_glyphs_set_style(NR_ARENA_GLYPHS(child), sg->style); - } + sg->nrstyle.set(style); nr_arena_item_request_update(NR_ARENA_ITEM(sg), NR_ARENA_ITEM_STATE_ALL, FALSE); } @@ -675,9 +442,8 @@ nr_arena_glyphs_group_set_paintbox(NRArenaGlyphsGroup *gg, NRRect const *pbox) gg->paintbox.x1 = pbox->x1; gg->paintbox.y1 = pbox->y1; } else { - /* fixme: We kill warning, although not sure what to do here (Lauris) */ gg->paintbox.x0 = gg->paintbox.y0 = 0.0F; - gg->paintbox.x1 = gg->paintbox.y1 = 256.0F; + gg->paintbox.x1 = gg->paintbox.y1 = -1.0F; } nr_arena_item_request_update(NR_ARENA_ITEM(gg), NR_ARENA_ITEM_STATE_ALL, FALSE); diff --git a/src/display/nr-arena-glyphs.h b/src/display/nr-arena-glyphs.h index b56a9f56c..c43095cb2 100644 --- a/src/display/nr-arena-glyphs.h +++ b/src/display/nr-arena-glyphs.h @@ -18,9 +18,10 @@ #define NR_IS_ARENA_GLYPHS(obj) (NR_CHECK_INSTANCE_TYPE ((obj), NR_TYPE_ARENA_GLYPHS)) #include "libnrtype/nrtype-forward.h" - +#include "display/display-forward.h" #include "forward.h" #include "display/nr-arena-item.h" +#include "display/nr-style.h" #define test_glyph_liv @@ -32,22 +33,12 @@ NRType nr_arena_glyphs_get_type (void); struct NRArenaGlyphs : public NRArenaItem { /* Glyphs data */ - SPStyle *style; Geom::Affine g_transform; + font_instance *font; gint glyph; - - raster_font *rfont; - raster_font *sfont; float x, y; -// Geom::Affine cached_tr; -// Shape *cached_shp; -// bool cached_shp_dirty; -// bool cached_style_dirty; - -// Shape *stroke_shp; - static NRArenaGlyphs *create(NRArena *arena) { NRArenaGlyphs *obj=reinterpret_cast<NRArenaGlyphs *>(nr_object_new(NR_TYPE_ARENA_GLYPHS)); obj->init(arena); @@ -79,11 +70,8 @@ typedef struct NRArenaGlyphsGroupClass NRArenaGlyphsGroupClass; NRType nr_arena_glyphs_group_get_type (void); struct NRArenaGlyphsGroup : public NRArenaGroup { - //SPStyle *style; NRRect paintbox; - /* State data */ - SPPainter *fill_painter; - SPPainter *stroke_painter; + NRStyle nrstyle; static NRArenaGlyphsGroup *create(NRArena *arena) { NRArenaGlyphsGroup *obj=reinterpret_cast<NRArenaGlyphsGroup *>(nr_object_new(NR_TYPE_ARENA_GLYPHS_GROUP)); diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp index 6c6043b2c..97f92d02d 100644 --- a/src/display/nr-arena-group.cpp +++ b/src/display/nr-arena-group.cpp @@ -14,12 +14,10 @@ #include "display/nr-arena-group.h" #include "display/nr-filter.h" -#include "display/nr-filter-gaussian.h" #include "display/nr-filter-types.h" #include "style.h" #include "sp-filter.h" #include "sp-filter-reference.h" -#include "sp-gaussian-blur.h" #include "filters/blend.h" #include "display/nr-filter-blend.h" #include "helper/geom.h" @@ -35,7 +33,7 @@ static void nr_arena_group_set_child_position (NRArenaItem *item, NRArenaItem *c static unsigned int nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset); static unsigned int nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags); -static unsigned int nr_arena_group_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb); +static unsigned int nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area); static NRArenaItem *nr_arena_group_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); static NRArenaItemClass *parent_class; @@ -233,7 +231,7 @@ nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock } static unsigned int -nr_arena_group_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb) +nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) { NRArenaGroup *group = NR_ARENA_GROUP (item); @@ -241,7 +239,7 @@ nr_arena_group_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb) /* Just compose children into parent buffer */ for (NRArenaItem *child = group->children; child != NULL; child = child->next) { - ret = nr_arena_item_invoke_clip (child, area, pb); + ret = nr_arena_item_invoke_clip (ct, child, area); if (ret & NR_ARENA_ITEM_STATE_INVALID) break; } diff --git a/src/display/nr-arena-image.cpp b/src/display/nr-arena-image.cpp index 6539ae4d2..cb1bc5849 100644 --- a/src/display/nr-arena-image.cpp +++ b/src/display/nr-arena-image.cpp @@ -12,20 +12,15 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <libnr/nr-compose-transform.h> #include <2geom/transforms.h> -#include <libnr/nr-blit.h> #include "../preferences.h" #include "nr-arena-image.h" #include "style.h" +#include "display/cairo-utils.h" #include "display/nr-arena.h" #include "display/nr-filter.h" -#include "display/nr-filter-gaussian.h" #include "sp-filter.h" #include "sp-filter-reference.h" -#include "sp-gaussian-blur.h" -#include "filters/blend.h" -#include "display/nr-filter-blend.h" int nr_arena_image_x_sample = 1; int nr_arena_image_y_sample = 1; @@ -42,6 +37,7 @@ static void nr_arena_image_finalize (NRObject *object); static unsigned int nr_arena_image_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset); static unsigned int nr_arena_image_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags); static NRArenaItem *nr_arena_image_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); +static Geom::Rect nr_arena_image_rect (NRArenaImage *image); static NRArenaItemClass *parent_class; @@ -82,14 +78,11 @@ nr_arena_image_class_init (NRArenaImageClass *klass) static void nr_arena_image_init (NRArenaImage *image) { - image->px = NULL; - - image->pxw = image->pxh = image->pxrs = 0; - image->x = image->y = 0.0; - image->width = 256.0; - image->height = 256.0; - - image->grid2px.setIdentity(); + image->pixbuf = NULL; + image->ctm.setIdentity(); + image->clipbox = Geom::Rect(); + image->ox = image->oy = 0.0; + image->sx = image->sy = 1.0; image->style = 0; image->render_opacity = TRUE; @@ -100,7 +93,12 @@ nr_arena_image_finalize (NRObject *object) { NRArenaImage *image = NR_ARENA_IMAGE (object); - image->px = NULL; + if (image->pixbuf != NULL) { + g_object_unref(image->pixbuf); + cairo_surface_destroy(image->surface); + } + if (image->style) + sp_style_unref(image->style); ((NRObjectClass *) parent_class)->finalize (object); } @@ -108,54 +106,24 @@ nr_arena_image_finalize (NRObject *object) static unsigned int nr_arena_image_update( NRArenaItem *item, NRRectL */*area*/, NRGC *gc, unsigned int /*state*/, unsigned int /*reset*/ ) { - Geom::Affine grid2px; - // clear old bbox nr_arena_item_request_render(item); NRArenaImage *image = NR_ARENA_IMAGE (item); /* Copy affine */ - grid2px = gc->transform.inverse(); - double hscale, vscale; // todo: replace with Geom::Scale - if (image->px) { - hscale = image->pxw / image->width; - vscale = image->pxh / image->height; - } else { - hscale = 1.0; - vscale = 1.0; - } - - image->grid2px[0] = grid2px[0] * hscale; - image->grid2px[2] = grid2px[2] * hscale; - image->grid2px[4] = grid2px[4] * hscale; - image->grid2px[1] = grid2px[1] * vscale; - image->grid2px[3] = grid2px[3] * vscale; - image->grid2px[5] = grid2px[5] * vscale; - - image->grid2px[4] -= image->x * hscale; - image->grid2px[5] -= image->y * vscale; + image->ctm = gc->transform; /* Calculate bbox */ - if (image->px) { + if (image->pixbuf) { NRRect bbox; - bbox.x0 = image->x; - bbox.y0 = image->y; - bbox.x1 = image->x + image->width; - bbox.y1 = image->y + image->height; - - image->c00 = (Geom::Point(bbox.x0, bbox.y0) * gc->transform); - image->c01 = (Geom::Point(bbox.x0, bbox.y1) * gc->transform); - image->c10 = (Geom::Point(bbox.x1, bbox.y0) * gc->transform); - image->c11 = (Geom::Point(bbox.x1, bbox.y1) * gc->transform); + Geom::Rect r = nr_arena_image_rect(image) * gc->transform; - nr_rect_d_matrix_transform (&bbox, &bbox, gc->transform); - - item->bbox.x0 = static_cast<NR::ICoord>(floor(bbox.x0)); // Floor gives the coordinate in which the point resides - item->bbox.y0 = static_cast<NR::ICoord>(floor(bbox.y0)); - item->bbox.x1 = static_cast<NR::ICoord>(ceil (bbox.x1)); // Ceil gives the first coordinate beyond the point - item->bbox.y1 = static_cast<NR::ICoord>(ceil (bbox.y1)); + item->bbox.x0 = floor(r.left()); // Floor gives the coordinate in which the point resides + item->bbox.y0 = floor(r.top()); + item->bbox.x1 = ceil(r.right()); // Ceil gives the first coordinate beyond the point + item->bbox.y1 = ceil(r.bottom()); } else { item->bbox.x0 = (int) gc->transform[4]; item->bbox.y0 = (int) gc->transform[5]; @@ -166,78 +134,63 @@ nr_arena_image_update( NRArenaItem *item, NRRectL */*area*/, NRGC *gc, unsigned return NR_ARENA_ITEM_STATE_ALL; } -#define FBITS 12 -#define b2i (image->grid2px) - static unsigned int -nr_arena_image_render( cairo_t *ct, NRArenaItem *item, NRRectL */*area*/, NRPixBlock *pb, unsigned int /*flags*/ ) +nr_arena_image_render( cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int /*flags*/ ) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - nr_arena_image_x_sample = prefs->getInt("/options/bitmapoversample/value", 1); - nr_arena_image_y_sample = nr_arena_image_x_sample; + if (!ct) + return item->state; bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); NRArenaImage *image = NR_ARENA_IMAGE (item); - Geom::Affine d2s; - - d2s[0] = b2i[0]; - d2s[1] = b2i[1]; - d2s[2] = b2i[2]; - d2s[3] = b2i[3]; - d2s[4] = b2i[0] * pb->area.x0 + b2i[2] * pb->area.y0 + b2i[4]; - d2s[5] = b2i[1] * pb->area.x0 + b2i[3] * pb->area.y0 + b2i[5]; - if (!outline) { + if (!image->pixbuf) return item->state; - if (!image->px) return item->state; + // FIXME: at the moment gdk_cairo_set_source_pixbuf creates an ARGB copy + // of the pixbuf. Fix this in Cairo and/or GDK. + cairo_save(ct); + ink_cairo_transform(ct, image->ctm); - guint32 Falpha = item->opacity; - if (Falpha < 1) return item->state; + cairo_new_path(ct); + cairo_rectangle(ct, image->clipbox.left(), image->clipbox.top(), + image->clipbox.width(), image->clipbox.height()); + cairo_clip(ct); - unsigned char * dpx = NR_PIXBLOCK_PX (pb); - int const drs = pb->rs; - int const dw = pb->area.x1 - pb->area.x0; - int const dh = pb->area.y1 - pb->area.y0; + cairo_translate(ct, image->ox, image->oy); + cairo_scale(ct, image->sx, image->sy); - unsigned char * spx = image->px; - int const srs = image->pxrs; - int const sw = image->pxw; - int const sh = image->pxh; + cairo_set_source_surface(ct, image->surface, 0, 0); - if (pb->mode == NR_PIXBLOCK_MODE_R8G8B8) { - /* fixme: This is not implemented yet (Lauris) */ - /* nr_R8G8B8_R8G8B8_R8G8B8A8_N_TRANSFORM (dpx, dw, dh, drs, spx, sw, sh, srs, d2s, Falpha, nr_arena_image_x_sample, nr_arena_image_y_sample); */ - } else if (pb->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) { - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM (dpx, dw, dh, drs, spx, sw, sh, srs, d2s, Falpha, nr_arena_image_x_sample, nr_arena_image_y_sample); - } else if (pb->mode == NR_PIXBLOCK_MODE_R8G8B8A8N) { - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_TRANSFORM (dpx, dw, dh, drs, spx, sw, sh, srs, d2s, Falpha, nr_arena_image_x_sample, nr_arena_image_y_sample); + cairo_matrix_t tt; + Geom::Affine total; + cairo_get_matrix(ct, &tt); + ink_matrix_to_2geom(total, tt); + + if (total.expansionX() > 1.0 || total.expansionY() > 1.0) { + cairo_pattern_t *p = cairo_get_source(ct); + cairo_pattern_set_filter(p, CAIRO_FILTER_NEAREST); } - pb->empty = FALSE; + cairo_paint_with_alpha(ct, ((double) item->opacity) / 255.0); + cairo_restore(ct); } else { // outline; draw a rect instead - - if (!ct) - return item->state; - + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); guint32 rgba = prefs->getInt("/options/wireframecolors/images", 0xff0000ff); - // FIXME: we use RGBA buffers but cairo writes BGRA (on i386), so we must cheat - // by setting color channels in the "wrong" order - cairo_set_source_rgba(ct, SP_RGBA32_B_F(rgba), SP_RGBA32_G_F(rgba), SP_RGBA32_R_F(rgba), SP_RGBA32_A_F(rgba)); - cairo_set_line_width(ct, 0.5); + cairo_save(ct); + ink_cairo_transform(ct, image->ctm); + cairo_new_path(ct); - Geom::Point shift(pb->area.x0, pb->area.y0); - Geom::Point c00 = image->c00 - shift; - Geom::Point c01 = image->c01 - shift; - Geom::Point c11 = image->c11 - shift; - Geom::Point c10 = image->c10 - shift; + Geom::Rect r = nr_arena_image_rect (image); + Geom::Point c00 = r.corner(0); + Geom::Point c01 = r.corner(3); + Geom::Point c11 = r.corner(2); + Geom::Point c10 = r.corner(1); cairo_move_to (ct, c00[Geom::X], c00[Geom::Y]); - // the box cairo_line_to (ct, c10[Geom::X], c10[Geom::Y]); cairo_line_to (ct, c11[Geom::X], c11[Geom::Y]); @@ -247,12 +200,12 @@ nr_arena_image_render( cairo_t *ct, NRArenaItem *item, NRRectL */*area*/, NRPixB cairo_line_to (ct, c11[Geom::X], c11[Geom::Y]); cairo_move_to (ct, c10[Geom::X], c10[Geom::Y]); cairo_line_to (ct, c01[Geom::X], c01[Geom::Y]); + cairo_restore(ct); + cairo_set_line_width(ct, 0.5); + ink_cairo_set_source_rgba32(ct, rgba); cairo_stroke(ct); - - pb->empty = FALSE; } - return item->state; } @@ -282,33 +235,47 @@ nr_arena_image_pick( NRArenaItem *item, Geom::Point p, double delta, unsigned in { NRArenaImage *image = NR_ARENA_IMAGE (item); - if (!image->px) return NULL; + if (!image->pixbuf) return NULL; bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); if (outline) { + Geom::Rect r = nr_arena_image_rect (image); + + Geom::Point c00 = r.corner(0); + Geom::Point c01 = r.corner(3); + Geom::Point c11 = r.corner(2); + Geom::Point c10 = r.corner(1); // frame - if (distance_to_segment (p, image->c00, image->c10) < delta) return item; - if (distance_to_segment (p, image->c10, image->c11) < delta) return item; - if (distance_to_segment (p, image->c11, image->c01) < delta) return item; - if (distance_to_segment (p, image->c01, image->c00) < delta) return item; + if (distance_to_segment (p, c00, c10) < delta) return item; + if (distance_to_segment (p, c10, c11) < delta) return item; + if (distance_to_segment (p, c11, c01) < delta) return item; + if (distance_to_segment (p, c01, c00) < delta) return item; // diagonals - if (distance_to_segment (p, image->c00, image->c11) < delta) return item; - if (distance_to_segment (p, image->c10, image->c01) < delta) return item; + if (distance_to_segment (p, c00, c11) < delta) return item; + if (distance_to_segment (p, c10, c01) < delta) return item; return NULL; } else { - unsigned char *const pixels = image->px; - int const width = image->pxw; - int const height = image->pxh; - int const rowstride = image->pxrs; - Geom::Point tp = p * image->grid2px; - int const ix = (int)(tp[Geom::X]); - int const iy = (int)(tp[Geom::Y]); + unsigned char *const pixels = gdk_pixbuf_get_pixels(image->pixbuf); + int const width = gdk_pixbuf_get_width(image->pixbuf); + int const height = gdk_pixbuf_get_height(image->pixbuf); + int const rowstride = gdk_pixbuf_get_rowstride(image->pixbuf); + + Geom::Point tp = p * image->ctm.inverse(); + Geom::Rect r = nr_arena_image_rect(image); + + if (!r.contains(tp)) + return NULL; + + double vw = width * image->sx; + double vh = height * image->sy; + int ix = floor((tp[Geom::X] - image->ox) / vw * width); + int iy = floor((tp[Geom::Y] - image->oy) / vh * height); if ((ix < 0) || (iy < 0) || (ix >= width) || (iy >= height)) return NULL; @@ -319,32 +286,79 @@ nr_arena_image_pick( NRArenaItem *item, Geom::Point p, double delta, unsigned in } } +Geom::Rect +nr_arena_image_rect (NRArenaImage *image) +{ + Geom::Rect r = image->clipbox; + + if (image->pixbuf) { + double pw = gdk_pixbuf_get_width(image->pixbuf); + double ph = gdk_pixbuf_get_height(image->pixbuf); + double vw = pw * image->sx; + double vh = ph * image->sy; + Geom::Point p(image->ox, image->oy); + Geom::Point wh(vw, vh); + Geom::Rect view(p, p+wh); + Geom::OptRect res = Geom::intersect(r, view); + r = res ? *res : r; + } + + return r; +} + /* Utility */ void -nr_arena_image_set_pixels (NRArenaImage *image, unsigned char const *px, unsigned int pxw, unsigned int pxh, unsigned int pxrs) +nr_arena_image_set_argb32_pixbuf (NRArenaImage *image, GdkPixbuf *pb) +{ + nr_return_if_fail (image != NULL); + nr_return_if_fail (NR_IS_ARENA_IMAGE (image)); + + // when done in this order, it won't break if pb == image->pixbuf and the refcount is 1 + if (pb != NULL) { + g_object_ref (pb); + } + if (image->pixbuf != NULL) { + g_object_unref(image->pixbuf); + cairo_surface_destroy(image->surface); + } + image->pixbuf = pb; + image->surface = pb ? ink_cairo_surface_create_for_argb32_pixbuf(pb) : NULL; + + nr_arena_item_request_update (NR_ARENA_ITEM (image), NR_ARENA_ITEM_STATE_ALL, FALSE); +} + +void +nr_arena_image_set_clipbox (NRArenaImage *image, Geom::Rect const &clip) +{ + nr_return_if_fail (image != NULL); + nr_return_if_fail (NR_IS_ARENA_IMAGE (image)); + + image->clipbox = clip; + + nr_arena_item_request_update (NR_ARENA_ITEM (image), NR_ARENA_ITEM_STATE_ALL, FALSE); +} + +void +nr_arena_image_set_origin (NRArenaImage *image, Geom::Point const &origin) { nr_return_if_fail (image != NULL); nr_return_if_fail (NR_IS_ARENA_IMAGE (image)); - image->px = (unsigned char *) px; - image->pxw = pxw; - image->pxh = pxh; - image->pxrs = pxrs; + image->ox = origin[Geom::X]; + image->oy = origin[Geom::Y]; nr_arena_item_request_update (NR_ARENA_ITEM (image), NR_ARENA_ITEM_STATE_ALL, FALSE); } void -nr_arena_image_set_geometry (NRArenaImage *image, double x, double y, double width, double height) +nr_arena_image_set_scale (NRArenaImage *image, double sx, double sy) { nr_return_if_fail (image != NULL); nr_return_if_fail (NR_IS_ARENA_IMAGE (image)); - image->x = x; - image->y = y; - image->width = width; - image->height = height; + image->sx = sx; + image->sy = sy; nr_arena_item_request_update (NR_ARENA_ITEM (image), NR_ARENA_ITEM_STATE_ALL, FALSE); } diff --git a/src/display/nr-arena-image.h b/src/display/nr-arena-image.h index c8d1525dc..6fa9223dd 100644 --- a/src/display/nr-arena-image.h +++ b/src/display/nr-arena-image.h @@ -13,28 +13,25 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <2geom/rect.h> +#include "nr-arena-item.h" +#include "style.h" + #define NR_TYPE_ARENA_IMAGE (nr_arena_image_get_type ()) #define NR_ARENA_IMAGE(o) (NR_CHECK_INSTANCE_CAST ((o), NR_TYPE_ARENA_IMAGE, NRArenaImage)) #define NR_IS_ARENA_IMAGE(o) (NR_CHECK_INSTANCE_TYPE ((o), NR_TYPE_ARENA_IMAGE)) -#include "nr-arena-item.h" -#include "style.h" - NRType nr_arena_image_get_type (void); struct NRArenaImage : public NRArenaItem { - unsigned char *px; - unsigned int pxw; - unsigned int pxh; - unsigned int pxrs; - - double x, y; - double width, height; + GdkPixbuf *pixbuf; + cairo_surface_t *surface; - Geom::Point c00, c01, c11, c10; // all 4 corners of the image, for outline mode rect - - /* From GRID to PIXELS */ - Geom::Affine grid2px; + Geom::Affine ctm; + Geom::Rect clipbox; + double ox, oy; + double sx, sy; SPStyle *style; @@ -49,10 +46,11 @@ struct NRArenaImageClass { NRArenaItemClass parent_class; }; -void nr_arena_image_set_pixels (NRArenaImage *image, unsigned char const *px, unsigned int pxw, unsigned int pxh, unsigned int pxrs); -void nr_arena_image_set_geometry (NRArenaImage *image, double x, double y, double width, double height); +void nr_arena_image_set_argb32_pixbuf (NRArenaImage *image, GdkPixbuf *pb); void nr_arena_image_set_style (NRArenaImage *image, SPStyle *style); - +void nr_arena_image_set_clipbox (NRArenaImage *image, Geom::Rect const &clip); +void nr_arena_image_set_origin (NRArenaImage *image, Geom::Point const &origin); +void nr_arena_image_set_scale (NRArenaImage *image, double sx, double sy); #endif diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index 6a5b7b5ba..8787c1033 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -17,9 +17,10 @@ #include <cstring> #include <string> +#include <cairomm/cairomm.h> -#include <libnr/nr-blit.h> -#include <libnr/nr-pixops.h> +#include "display/cairo-utils.h" +#include "display/cairo-templates.h" #include "nr-arena.h" #include "nr-arena-item.h" #include "gc-core.h" @@ -83,6 +84,7 @@ nr_arena_item_init (NRArenaItem *item) memset (&item->bbox, 0, sizeof (item->bbox)); memset (&item->drawbox, 0, sizeof (item->drawbox)); item->transform = NULL; + item->ctm.setIdentity(); item->opacity = 255; item->render_opacity = FALSE; @@ -104,6 +106,11 @@ nr_arena_item_private_finalize (NRObject *object) item->px = NULL; item->transform = NULL; + if (item->clip) + nr_arena_item_detach(item, item->clip); + if (item->mask) + nr_arena_item_detach(item, item->mask); + ((NRObjectClass *) (parent_class))->finalize (object); } @@ -258,12 +265,15 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, if (item->state & NR_ARENA_ITEM_STATE_INVALID) return item->state; - // get a copy of bbox - memcpy(&item->drawbox, &item->bbox, sizeof(item->bbox)); - /* Enlarge the drawbox to contain filter effects */ - if (item->filter && filter) { - item->filter->bbox_enlarge (item->drawbox); + if (item->filter && filter && item->item_bbox) { + item->drawbox.x0 = item->item_bbox->min()[Geom::X]; + item->drawbox.y0 = item->item_bbox->min()[Geom::Y]; + item->drawbox.x1 = item->item_bbox->max()[Geom::X]; + item->drawbox.y1 = item->item_bbox->max()[Geom::Y]; + item->filter->compute_drawbox (item, item->drawbox); + } else { + memcpy(&item->drawbox, &item->bbox, sizeof(item->bbox)); } // fixme: to fix the display glitches, in outline mode bbox must be a combination of // full item bbox and its clip and mask (after we have the API to get these) @@ -301,11 +311,16 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, return item->state; } -/** - * Render item to pixblock. - * - * \return Has NR_ARENA_ITEM_STATE_RENDER set on success. - */ +struct MaskLuminanceToAlpha { + guint32 operator()(guint32 in) { + EXTRACT_ARGB32(in, a, r, g, b) + // the operation of unpremul -> luminance-to-alpha -> multiply by alpha + // is equivalent to luminance-to-alpha on premultiplied color values + // original computation in double: r*0.2125 + g*0.7154 + b*0.0721 + guint32 ao = r*109 + g*366 + b*37; // coeffs add up to 512 + return ((ao + 256) << 15) & 0xff000000; // equivalent to ((ao + 256) / 512) << 24 + } +}; unsigned int nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area, @@ -314,13 +329,13 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); bool filter = (item->arena->rendermode != Inkscape::RENDERMODE_OUTLINE && item->arena->rendermode != Inkscape::RENDERMODE_NO_FILTERS); - bool print_colors = (item->arena->colorrendermode == Inkscape::COLORRENDERMODE_PRINT_COLORS_PREVIEW); nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID); nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NR_ARENA_ITEM_STATE_INVALID); nr_return_val_if_fail (item->state & NR_ARENA_ITEM_STATE_BBOX, item->state); + if (!ct) return item->state; #ifdef NR_ARENA_ITEM_VERBOSE g_message ("Invoke render %p on %p: %d %d - %d %d, %d %d - %d %d", item, pb, @@ -334,6 +349,8 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area if (!item->visible) return item->state | NR_ARENA_ITEM_STATE_RENDER; + // carea is the bounding box for intermediate rendering. + // NOTE: carea might be larger than area, because of filter effects. NRRectL carea; nr_rect_l_intersect (&carea, area, &item->drawbox); if (nr_rect_l_test_empty(carea)) @@ -344,272 +361,152 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area } if (outline) { - // No caching in outline mode for now; investigate if it really gives any advantage with cairo. - // Also no attempts to clip anything; just render everything: item, clip, mask - // First, render the object itself - unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, pb, flags); - if (state & NR_ARENA_ITEM_STATE_INVALID) { - /* Clean up and return error */ - item->state |= NR_ARENA_ITEM_STATE_INVALID; - return item->state; - } - - // render clip and mask, if any - guint32 saved_rgba = item->arena->outlinecolor; // save current outline color - // render clippath as an object, using a different color - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (item->clip) { - item->arena->outlinecolor = prefs->getInt("/options/wireframecolors/clips", 0x00ff00ff); // green clips - NR_ARENA_ITEM_VIRTUAL (item->clip, render) (ct, item->clip, &carea, pb, flags); - } - // render mask as an object, using a different color - if (item->mask) { - item->arena->outlinecolor = prefs->getInt("/options/wireframecolors/masks", 0x0000ffff); // blue masks - NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ct, item->mask, &carea, pb, flags); - } - item->arena->outlinecolor = saved_rgba; // restore outline color + // No caching in outline mode for now; investigate if it really gives any advantage with cairo. + // Also no attempts to clip anything; just render everything: item, clip, mask + // First, render the object itself + unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, pb, flags); + if (state & NR_ARENA_ITEM_STATE_INVALID) { + /* Clean up and return error */ + item->state |= NR_ARENA_ITEM_STATE_INVALID; + return item->state; + } - return item->state | NR_ARENA_ITEM_STATE_RENDER; - } + // render clip and mask, if any + guint32 saved_rgba = item->arena->outlinecolor; // save current outline color + // render clippath as an object, using a different color + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (item->clip) { + item->arena->outlinecolor = prefs->getInt("/options/wireframecolors/clips", 0x00ff00ff); // green clips + NR_ARENA_ITEM_VIRTUAL (item->clip, render) (ct, item->clip, &carea, pb, flags); + } + // render mask as an object, using a different color + if (item->mask) { + item->arena->outlinecolor = prefs->getInt("/options/wireframecolors/masks", 0x0000ffff); // blue masks + NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ct, item->mask, &carea, pb, flags); + } + item->arena->outlinecolor = saved_rgba; // restore outline color - NRPixBlock cpb; - if (item->px) { - /* Has cache pixblock, render this and return */ - nr_pixblock_setup_extern (&cpb, NR_PIXBLOCK_MODE_R8G8B8A8P, - /* fixme: This probably cannot overflow, because we render only if visible */ - /* fixme: and pixel cache is there only for small items */ - /* fixme: But this still needs extra check (Lauris) */ - item->drawbox.x0, item->drawbox.y0, - item->drawbox.x1, item->drawbox.y1, - item->px, - 4 * (item->drawbox.x1 - item->drawbox.x0), FALSE, - FALSE); - nr_blit_pixblock_pixblock (pb, &cpb); - nr_pixblock_release (&cpb); - pb->empty = FALSE; return item->state | NR_ARENA_ITEM_STATE_RENDER; } - NRPixBlock *dpb = pb; - - /* Setup cache if we can */ - if ((!(flags & NR_ARENA_ITEM_RENDER_NO_CACHE)) && - (carea.x0 <= item->drawbox.x0) && (carea.y0 <= item->drawbox.y0) && - (carea.x1 >= item->drawbox.x1) && (carea.y1 >= item->drawbox.y1) && - (((item->drawbox.x1 - item->drawbox.x0) * (item->drawbox.y1 - - item->drawbox.y0)) <= 4096)) { - // Item drawbox is fully in renderable area and size is acceptable - carea.x0 = item->drawbox.x0; - carea.y0 = item->drawbox.y0; - carea.x1 = item->drawbox.x1; - carea.y1 = item->drawbox.y1; - item->px = - new (GC::ATOMIC) unsigned char[4 * (carea.x1 - carea.x0) * - (carea.y1 - carea.y0)]; - nr_pixblock_setup_extern (&cpb, NR_PIXBLOCK_MODE_R8G8B8A8P, carea.x0, - carea.y0, carea.x1, carea.y1, item->px, - 4 * (carea.x1 - carea.x0), TRUE, TRUE); - cpb.visible_area = pb->visible_area; - dpb = &cpb; - // Set nocache flag for downstream rendering - flags |= NR_ARENA_ITEM_RENDER_NO_CACHE; - } + using namespace Inkscape; - /* Determine, whether we need temporary buffer */ - if (item->clip || item->mask - || ((item->opacity != 255) && !item->render_opacity) - || (item->filter && filter) || item->background_new) { - - /* Setup and render item buffer */ - NRPixBlock ipb; - nr_pixblock_setup_fast (&ipb, NR_PIXBLOCK_MODE_R8G8B8A8P, - carea.x0, carea.y0, carea.x1, carea.y1, - TRUE); - - // if memory allocation failed, abort render - if (ipb.size != NR_PIXBLOCK_SIZE_TINY && ipb.data.px == NULL) { - nr_pixblock_release (&ipb); - return (item->state); - } + // clipping and masks + unsigned int state; - /* If background access is used, save the pixblock address. - * This address is set to NULL at the end of this block */ - if (item->background_new) { - item->background_pb = &ipb; - } + cairo_t *this_ct = ct; + NRRectL *this_area = const_cast<NRRectL*>(area); - ipb.visible_area = pb->visible_area; - if (item->filter && filter) { - item->filter->area_enlarge (ipb.visible_area, item); - } + bool needs_intermediate_rendering = false; + bool &nir = needs_intermediate_rendering; + bool needs_opacity = (item->opacity != 255 && !item->render_opacity); + + // this item needs an intermediate rendering if: + nir |= (item->mask != NULL); // 1. it has a mask + nir |= (item->filter != NULL && filter); // 2. it has a filter + nir |= needs_opacity; // 3. it is non-opaque + + double opacity = static_cast<double>(item->opacity) / 255.0; + + if (needs_intermediate_rendering) { + cairo_surface_t *intermediate = cairo_surface_create_similar( + cairo_get_target(ct), CAIRO_CONTENT_COLOR_ALPHA, + carea.x1 - carea.x0, carea.y1 - carea.y0); + this_ct = cairo_create(intermediate); + cairo_translate(this_ct, -carea.x0, -carea.y0); + this_area = &carea; + cairo_surface_destroy(intermediate); // the surface will be held in memory by this_ct + } else { + cairo_reference(this_ct); + } + + // The pipeline needs to be different for filters. + // First we render the item into an intermediate surface. Then the filter rotates + // the surface to user coordinates (if necessary) and runs the rendering. + // Once that's done we retrieve the result, rotating it back to screen coords. + // Clipping and masking happens after the filter result is ready. + if (item->filter && filter) { + } + + Cairo::Context cct(this_ct, true); + Cairo::Context base_ct(ct); + Cairo::RefPtr<Cairo::Pattern> mask; + CairoSave clipsave(ct); // RAII for save / restore + CairoGroup maskgroup(this_ct); // RAII for push_group / pop_group + CairoGroup drawgroup(this_ct); + CairoGroup maskopacitygroup(this_ct); - unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, &ipb, flags); + // always clip the base context, not the one on the intermediate surface + // this is because filters must be done before clipping + if (item->clip) { + clipsave.save(); + state = nr_arena_item_invoke_clip(ct, item->clip, const_cast<NRRectL*>(area)); if (state & NR_ARENA_ITEM_STATE_INVALID) { - /* Clean up and return error */ - nr_pixblock_release (&ipb); - if (dpb != pb) - nr_pixblock_release (dpb); item->state |= NR_ARENA_ITEM_STATE_INVALID; return item->state; } - ipb.empty = FALSE; - - /* Run filtering, if a filter is set for this object */ - if (item->filter && filter) { - item->filter->render (item, &ipb); - } + base_ct.clip(); + } - if (item->clip || item->mask) { - /* Setup mask pixblock */ - NRPixBlock mpb; - nr_pixblock_setup_fast (&mpb, NR_PIXBLOCK_MODE_A8, carea.x0, - carea.y0, carea.x1, carea.y1, TRUE); - - if (mpb.data.px != NULL) { // if memory allocation was successful - - mpb.visible_area = pb->visible_area; - /* Do clip if needed */ - if (item->clip) { - state = nr_arena_item_invoke_clip (item->clip, &carea, &mpb); - if (state & NR_ARENA_ITEM_STATE_INVALID) { - /* Clean up and return error */ - nr_pixblock_release (&mpb); - nr_pixblock_release (&ipb); - if (dpb != pb) - nr_pixblock_release (dpb); - item->state |= NR_ARENA_ITEM_STATE_INVALID; - return item->state; - } - mpb.empty = FALSE; - } - /* Do mask if needed */ - if (item->mask) { - NRPixBlock tpb; - /* Set up yet another temporary pixblock */ - nr_pixblock_setup_fast (&tpb, NR_PIXBLOCK_MODE_R8G8B8A8N, - carea.x0, carea.y0, carea.x1, - carea.y1, TRUE); - - if (tpb.data.px != NULL) { // if memory allocation was successful - - tpb.visible_area = pb->visible_area; - unsigned int state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ct, item->mask, &carea, &tpb, flags); - if (state & NR_ARENA_ITEM_STATE_INVALID) { - /* Clean up and return error */ - nr_pixblock_release (&tpb); - nr_pixblock_release (&mpb); - nr_pixblock_release (&ipb); - if (dpb != pb) - nr_pixblock_release (dpb); - item->state |= NR_ARENA_ITEM_STATE_INVALID; - return item->state; - } - /* Composite with clip */ - if (item->clip) { - int x, y; - for (y = carea.y0; y < carea.y1; y++) { - unsigned char *s, *d; - s = NR_PIXBLOCK_PX (&tpb) + (y - - carea.y0) * tpb.rs; - d = NR_PIXBLOCK_PX (&mpb) + (y - - carea.y0) * mpb.rs; - for (x = carea.x0; x < carea.x1; x++) { - // See below for calculation - unsigned int m; - m = NR_PREMUL_112 ( (NR_PREMUL_112 (s[0], 54) + - NR_PREMUL_112 (s[1], 183) + - NR_PREMUL_112 (s[2], 19) ) >> 8, s[3]); - d[0] = FAST_DIV_ROUND < 255 * 255 > ( NR_PREMUL_123 (d[0], m)); - s += 4; - d += 1; - } - } - } else { - int x, y; - for (y = carea.y0; y < carea.y1; y++) { - unsigned char *s, *d; - s = NR_PIXBLOCK_PX (&tpb) + (y - - carea.y0) * tpb.rs; - d = NR_PIXBLOCK_PX (&mpb) + (y - - carea.y0) * mpb.rs; - for (x = carea.x0; x < carea.x1; x++) { - unsigned int m; - // m = NR_PREMUL_112 (s[0] + s[1] + s[2], s[3]); - // d[0] = FAST_DIV_ROUND < 3 * 255 > (m); - // Must use luminance to alpha from feColorMatrix. - // This is an approximation, optimized(?) for speed. - // 0.2125 * 256 = 54.4000 - // 0.7154 * 256 = 183.1424 - // 0.0721 * 256 = 18.4576 - m = NR_PREMUL_112 ( (NR_PREMUL_112 (s[0], 54) + - NR_PREMUL_112 (s[1], 183) + - NR_PREMUL_112 (s[2], 19) ) >> 8, s[3]); - d[0] = FAST_DIV_ROUND < 255 > (m); - s += 4; - d += 1; - } - } - mpb.empty = FALSE; - } - } - nr_pixblock_release (&tpb); - } - /* Multiply with opacity if needed */ - if ((item->opacity != 255) && !item->render_opacity - ) { - int x, y; - unsigned int a; - a = item->opacity; - for (y = carea.y0; y < carea.y1; y++) { - unsigned char *d; - d = NR_PIXBLOCK_PX (&mpb) + (y - carea.y0) * mpb.rs; - for (x = carea.x0; x < carea.x1; x++) { - d[0] = NR_PREMUL_111 (d[0], a); - d += 1; - } - } - } - /* Compose rendering pixblock int destination */ - nr_blit_pixblock_pixblock_mask (dpb, &ipb, &mpb); - } - nr_pixblock_release (&mpb); - } else { - if (item->render_opacity) { // opacity was already rendered in, just copy to dpb here - nr_blit_pixblock_pixblock(dpb, &ipb); - } else { // copy while multiplying by opacity - nr_blit_pixblock_pixblock_alpha (dpb, &ipb, item->opacity); - } + // render mask on the intermediate context and store it + if (item->mask) { + maskgroup.push_with_content(CAIRO_CONTENT_COLOR_ALPHA); + // handle opacity of a masked object by composing it with the mask + if (needs_opacity) { + maskopacitygroup.push(); } - nr_pixblock_release (&ipb); - dpb->empty = FALSE; - /* This pointer wouldn't be valid outside this block, so clear it */ - item->background_pb = NULL; - } else { - /* Just render */ - unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, dpb, flags); + state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (this_ct, item->mask, this_area, pb, flags); if (state & NR_ARENA_ITEM_STATE_INVALID) { - /* Clean up and return error */ - if (dpb != pb) - nr_pixblock_release (dpb); item->state |= NR_ARENA_ITEM_STATE_INVALID; return item->state; } - dpb->empty = FALSE; + if (needs_opacity) { + maskopacitygroup.pop_to_source(); + cct.paint_with_alpha(opacity); + } + mask = maskgroup.popmm(); + // convert luminance to alpha + cairo_pattern_t *p = mask->cobj(); + cairo_surface_t *s; + cairo_pattern_get_surface(p, &s); + ink_cairo_surface_filter(s, s, MaskLuminanceToAlpha()); } - if (dpb != pb) { - /* Have to blit from cache */ - nr_blit_pixblock_pixblock (pb, dpb); - nr_pixblock_release (dpb); - pb->empty = FALSE; - item->state |= NR_ARENA_ITEM_STATE_IMAGE; + // render the object (possibly to the intermediate surface) + state = NR_ARENA_ITEM_VIRTUAL (item, render) (this_ct, item, this_area, pb, flags); + if (state & NR_ARENA_ITEM_STATE_INVALID) { + /* Clean up and return error */ + item->state |= NR_ARENA_ITEM_STATE_INVALID; + return item->state; + } + + // apply filter + if (item->filter && filter) { + item->filter->render(item, ct, area, this_ct, &carea); + } + + if (needs_intermediate_rendering) { + cairo_surface_t *intermediate = cairo_get_target(this_ct); + cairo_set_source_surface(ct, intermediate, carea.x0, carea.y0); + if (mask) { + cairo_mask(ct, mask->cobj()); + // opacity of masked objects is handled by premultiplying the mask + } else { + // opacity of non-masked objects must be rendered explicitly + if (needs_opacity) { + cairo_paint_with_alpha(ct, opacity); + } else { + cairo_paint(ct); + } + } + cairo_set_source_rgba(ct,0,0,0,0); } return item->state | NR_ARENA_ITEM_STATE_RENDER; } unsigned int -nr_arena_item_invoke_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb) +nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) { nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID); nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), @@ -618,12 +515,12 @@ nr_arena_item_invoke_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb) * NR_ARENA_ITEM_STATE_CLIP (and showed a warning on the console); * anyone know why we stopped doing so? */ - nr_return_val_if_fail ((pb->area.x1 - pb->area.x0) >= + /*nr_return_val_if_fail ((pb->area.x1 - pb->area.x0) >= (area->x1 - area->x0), NR_ARENA_ITEM_STATE_INVALID); nr_return_val_if_fail ((pb->area.y1 - pb->area.y0) >= (area->y1 - area->y0), - NR_ARENA_ITEM_STATE_INVALID); + NR_ARENA_ITEM_STATE_INVALID);*/ #ifdef NR_ARENA_ITEM_VERBOSE printf ("Invoke clip by %p: %d %d - %d %d, item bbox %d %d - %d %d\n", @@ -635,7 +532,7 @@ nr_arena_item_invoke_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb) /* Need render that item */ if (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->clip) { return ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))-> - clip (item, area, pb); + clip (ct, item, area); } } @@ -663,7 +560,8 @@ nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point p, double delta, if (((x + delta) >= item->bbox.x0) && ((x - delta) < item->bbox.x1) && - ((y + delta) >= item->bbox.y0) && ((y - delta) < item->bbox.y1)) { + ((y + delta) >= item->bbox.y0) && ((y - delta) < item->bbox.y1)) + { if (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->pick) return ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))-> pick (item, p, delta, sticky); @@ -872,13 +770,7 @@ nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect &bbox) NRPixBlock * nr_arena_item_get_background (NRArenaItem const *item) { - if (item->background_new) { - return item->background_pb; - } else if (item->parent) { - return nr_arena_item_get_background (item->parent); - } else { - return NULL; - } + return NULL; } /* Helpers */ diff --git a/src/display/nr-arena-item.h b/src/display/nr-arena-item.h index ff9965b85..0fc4cbe48 100644 --- a/src/display/nr-arena-item.h +++ b/src/display/nr-arena-item.h @@ -1,6 +1,3 @@ -#ifndef __NR_ARENA_ITEM_H__ -#define __NR_ARENA_ITEM_H__ - /* * RGBA display list system for inkscape * @@ -13,6 +10,21 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifndef SEEN_DISPLAY_NR_ARENA_ITEM_H +#define SEEN_DISPLAY_NR_ARENA_ITEM_H + +#include <cairo.h> +#include <2geom/affine.h> +#include "libnr/nr-rect-l.h" +#include "libnr/nr-object.h" +#include "gc-soft-ptr.h" +#include "nr-arena-forward.h" + +namespace Inkscape { +namespace Filters { +class Filter; +} } + #define NR_TYPE_ARENA_ITEM (nr_arena_item_get_type ()) #define NR_ARENA_ITEM(o) (NR_CHECK_INSTANCE_CAST ((o), NR_TYPE_ARENA_ITEM, NRArenaItem)) #define NR_IS_ARENA_ITEM(o) (NR_CHECK_INSTANCE_TYPE ((o), NR_TYPE_ARENA_ITEM)) @@ -52,15 +64,6 @@ #define NR_ARENA_ITEM_RENDER_NO_CACHE (1 << 0) -#include <2geom/affine.h> -#include <libnr/nr-rect-l.h> -#include <libnr/nr-pixblock.h> -#include <libnr/nr-object.h> -#include "gc-soft-ptr.h" -#include "nr-arena-forward.h" -#include "display/nr-filter.h" -#include <cairo.h> - struct NRGC { NRGC(NRGC const *p) : parent(p) {} NRGC const *parent; @@ -84,35 +87,22 @@ struct NRArenaItem : public NRObject { /* Opacity itself */ unsigned int opacity : 8; - /* Key for secondary rendering */ - unsigned int key; - - /* BBox in grid coordinates */ - NRRectL bbox; - /* Redraw area in grid coordinates = bbox filter-enlarged and clipped/masked */ - NRRectL drawbox; - /* BBox in item coordinates - this should be a bounding box as - * specified in SVG standard. Required by filters. */ - Geom::OptRect item_bbox; - /* Our affine */ - Geom::Affine *transform; - /* Clip item */ - NRArenaItem *clip; - /* Mask item */ - NRArenaItem *mask; - /* Filter to be applied after rendering this object, NULL if none */ - Inkscape::Filters::Filter *filter; - /* Rendered buffer */ - unsigned char *px; - - /* Single data member */ - void *data; - - /* Current Transformation Matrix */ - Geom::Affine ctm; - - /* These hold background buffer state for filter rendering */ - NRPixBlock *background_pb; + unsigned int key; ///< Some SPItems can have more than one NRArenaItem, + ///this value is a hack used to distinguish between them + + NRRectL bbox; ///< Bounding box in pixel grid coordinates; (0,0) is at page origin + NRRectL drawbox; ///< Bounding box enlarged by filters, shrinked by clips and masks + Geom::OptRect item_bbox; ///< Bounding box in item coordinates, required by filters + Geom::Affine *transform; ///< Incremental transform of this item, as given by the transform= attribute + Geom::Affine ctm; ///< Total transform from pixel grid to item coords + NRArenaItem *clip; ///< Clipping path + NRArenaItem *mask; ///< Mask + Inkscape::Filters::Filter *filter; ///< Filter + unsigned char *px; ///< Render cache; unused + + void *data; ///< Anonymous data member - this is used to associate SPItems with arena items + + NRPixBlock *background_pb; ///< Background for filters; unused bool background_new; void init(NRArena *arena) { @@ -129,7 +119,7 @@ struct NRArenaItemClass : public NRObjectClass { unsigned int (* update) (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset); unsigned int (* render) (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags); - unsigned int (* clip) (NRArenaItem *item, NRRectL *area, NRPixBlock *pb); + unsigned int (* clip) (cairo_t *ct, NRArenaItem *item, NRRectL *area); NRArenaItem * (* pick) (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); }; @@ -159,7 +149,7 @@ unsigned int nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC unsigned int nr_arena_item_invoke_render(cairo_t *ct, NRArenaItem *item, NRRectL const *area, NRPixBlock *pb, unsigned int flags); -unsigned int nr_arena_item_invoke_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb); +unsigned int nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area); NRArenaItem *nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); void nr_arena_item_request_update (NRArenaItem *item, unsigned int reset, unsigned int propagate); @@ -194,8 +184,7 @@ NRArenaItem *nr_arena_item_detach (NRArenaItem *parent, NRArenaItem *child); #define NR_ARENA_ITEM_SET_KEY(i,k) (((NRArenaItem *) (i))->key = (k)) #define NR_ARENA_ITEM_GET_KEY(i) (((NRArenaItem *) (i))->key) - -#endif /* !__NR_ARENA_ITEM_H__ */ +#endif /* !SEEN_DISPLAY_NR_ARENA_ITEM_H */ /* Local Variables: diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp index 33a218e99..f278413b2 100644 --- a/src/display/nr-arena-shape.cpp +++ b/src/display/nr-arena-shape.cpp @@ -10,41 +10,30 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <cairo.h> #include <glib.h> #include <fenv.h> #include <typeinfo> -#include <cairo.h> +#include <2geom/curves.h> +#include <2geom/pathvector.h> #include <2geom/svg-path.h> #include <2geom/svg-path-parser.h> -#include <2geom/pathvector.h> -#include <2geom/curves.h> -#include "display/sp-canvas.h" +#include "display/cairo-utils.h" #include "display/canvas-arena.h" +#include "display/curve.h" #include "display/nr-arena.h" #include "display/nr-arena-shape.h" -#include "display/curve.h" -#include "display/grayscale.h" -#include "libnr/nr-pixops.h" -#include "libnr/nr-blit.h" -#include "libnr/nr-convert2geom.h" -#include "livarot/Path.h" -#include "livarot/float-line.h" -#include "livarot/int-line.h" -#include "style.h" -#include "inkscape-cairo.h" -#include "helper/geom.h" +#include "display/nr-filter.h" #include "helper/geom-curves.h" +#include "helper/geom.h" +#include "libnr/nr-convert2geom.h" +#include "preferences.h" #include "sp-filter.h" #include "sp-filter-reference.h" -#include "display/nr-filter.h" -#include "preferences.h" - +#include "style.h" #include "svg/svg.h" -//int showRuns=0; -void nr_pixblock_render_shape_mask_or(NRPixBlock &m,Shape* theS); - static void nr_arena_shape_class_init(NRArenaShapeClass *klass); static void nr_arena_shape_init(NRArenaShape *shape); static void nr_arena_shape_finalize(NRObject *object); @@ -56,7 +45,7 @@ static void nr_arena_shape_set_child_position(NRArenaItem *item, NRArenaItem *ch static guint nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset); static unsigned int nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags); -static guint nr_arena_shape_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb); +static guint nr_arena_shape_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area); static NRArenaItem *nr_arena_shape_pick(NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); static NRArenaItemClass *shape_parent_class; @@ -111,26 +100,13 @@ nr_arena_shape_init(NRArenaShape *shape) shape->style = NULL; shape->paintbox.x0 = shape->paintbox.y0 = 0.0F; shape->paintbox.x1 = shape->paintbox.y1 = 256.0F; - - shape->ctm.setIdentity(); - shape->fill_painter = NULL; - shape->stroke_painter = NULL; - shape->cached_fill = NULL; - shape->cached_stroke = NULL; - shape->cached_fpartialy = false; - shape->cached_spartialy = false; - shape->fill_shp = NULL; - shape->stroke_shp = NULL; - shape->delayed_shp = false; + shape->path = NULL; shape->approx_bbox.x0 = shape->approx_bbox.y0 = 0; shape->approx_bbox.x1 = shape->approx_bbox.y1 = 0; - shape->cached_fctm.setIdentity(); - shape->cached_sctm.setIdentity(); shape->markers = NULL; - shape->last_pick = NULL; shape->repick_after = 0; } @@ -140,15 +116,10 @@ nr_arena_shape_finalize(NRObject *object) { NRArenaShape *shape = (NRArenaShape *) object; - if (shape->fill_shp) delete shape->fill_shp; - if (shape->stroke_shp) delete shape->stroke_shp; - if (shape->cached_fill) delete shape->cached_fill; - if (shape->cached_stroke) delete shape->cached_stroke; - if (shape->fill_painter) sp_painter_free(shape->fill_painter); - if (shape->stroke_painter) sp_painter_free(shape->stroke_painter); - + if (shape->path) cairo_path_destroy(shape->path); if (shape->style) sp_style_unref(shape->style); if (shape->curve) shape->curve->unref(); + shape->last_pick = NULL; ((NRObjectClass *) shape_parent_class)->finalize(object); } @@ -227,10 +198,6 @@ nr_arena_shape_set_child_position(NRArenaItem *item, NRArenaItem *child, NRArena nr_arena_item_request_render(child); } -void nr_arena_shape_update_stroke(NRArenaShape *shape, NRGC* gc, NRRectL *area); -void nr_arena_shape_update_fill(NRArenaShape *shape, NRGC *gc, NRRectL *area, bool force_shape = false); -void nr_arena_shape_add_bboxes(NRArenaShape* shape, Geom::OptRect &bbox); - /** * Updates the arena shape 'item' and all of its children, including the markers. */ @@ -243,6 +210,7 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g unsigned int beststate = NR_ARENA_ITEM_STATE_ALL; + // update markers unsigned int newstate; for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) { newstate = nr_arena_item_invoke_update(child, area, gc, state, reset); @@ -251,7 +219,6 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g if (!(state & NR_ARENA_ITEM_STATE_RENDER)) { /* We do not have to create rendering structures */ - shape->ctm = gc->transform; if (state & NR_ARENA_ITEM_STATE_BBOX) { if (shape->curve) { boundingbox = bounds_exact_transformed(shape->curve->get_pathvector(), gc->transform); @@ -274,29 +241,36 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g } shape->delayed_shp=true; - shape->ctm = gc->transform; boundingbox = Geom::OptRect(); bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); + // clear Cairo data to force update + shape->nrstyle.update(); + if (shape->path) { + cairo_path_destroy(shape->path); + shape->path = NULL; + } + if (shape->curve) { boundingbox = bounds_exact_transformed(shape->curve->get_pathvector(), gc->transform); - if (boundingbox && (shape->_stroke.paint.type() != NRArenaShape::Paint::NONE || outline)) { + if (boundingbox && (shape->nrstyle.stroke.type != NRStyle::PAINT_NONE || outline)) { float width, scale; scale = gc->transform.descrim(); - width = MAX(0.125, shape->_stroke.width * scale); - if ( fabs(shape->_stroke.width * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord + width = MAX(0.125, shape->nrstyle.stroke_width * scale); + if ( fabs(shape->nrstyle.stroke_width * scale) > 0.01 ) { // FIXME: this is always true boundingbox->expandBy(width); } // those pesky miters, now - float miterMax=width*shape->_stroke.mitre_limit; + float miterMax = width * shape->nrstyle.miter_limit; if ( miterMax > 0.01 ) { - // grunt mode. we should compute the various miters instead (one for each point on the curve) + // grunt mode. we should compute the various miters instead + // (one for each point on the curve) boundingbox->expandBy(miterMax); } } - } + } /// \todo just write item->bbox = boundingbox if (boundingbox) { @@ -309,88 +283,17 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g } if ( area && nr_rect_l_test_intersect_ptr(area, &shape->approx_bbox) ) shape->delayed_shp=false; - /* Release state data */ - if (shape->fill_shp) { - delete shape->fill_shp; - shape->fill_shp = NULL; - } - if (shape->stroke_shp) { - delete shape->stroke_shp; - shape->stroke_shp = NULL; - } - if (shape->fill_painter) { - sp_painter_free(shape->fill_painter); - shape->fill_painter = NULL; - } - if (shape->stroke_painter) { - sp_painter_free(shape->stroke_painter); - shape->stroke_painter = NULL; - } + // TODO: compute a better bounding box that respects miters + item->bbox = shape->approx_bbox; if (!shape->curve || !shape->style || shape->curve->is_empty() || - (( shape->_fill.paint.type() == NRArenaShape::Paint::NONE ) && - ( shape->_stroke.paint.type() == NRArenaShape::Paint::NONE && !outline) )) + (( shape->nrstyle.fill.type != NRStyle::PAINT_NONE ) && + ( shape->nrstyle.stroke.type != NRStyle::PAINT_NONE && !outline) )) { - item->bbox = shape->approx_bbox; - return NR_ARENA_ITEM_STATE_ALL; - } - - /* Build state data */ - if ( shape->delayed_shp ) { - item->bbox=shape->approx_bbox; - } else { - nr_arena_shape_update_stroke(shape, gc, area); - nr_arena_shape_update_fill(shape, gc, area); - - boundingbox = Geom::OptRect(); - nr_arena_shape_add_bboxes(shape, boundingbox); - - /// \todo just write shape->approx_bbox = boundingbox - if (boundingbox) { - shape->approx_bbox.x0 = static_cast<NR::ICoord>(floor((*boundingbox)[0][0])); - shape->approx_bbox.y0 = static_cast<NR::ICoord>(floor((*boundingbox)[1][0])); - shape->approx_bbox.x1 = static_cast<NR::ICoord>(ceil ((*boundingbox)[0][1])); - shape->approx_bbox.y1 = static_cast<NR::ICoord>(ceil ((*boundingbox)[1][1])); - } else { - shape->approx_bbox = NR_RECT_L_EMPTY; - } - } - - if (!boundingbox) + //item->bbox = shape->approx_bbox; return NR_ARENA_ITEM_STATE_ALL; - - /// \todo just write item->bbox = boundingbox - item->bbox.x0 = static_cast<NR::ICoord>(floor((*boundingbox)[0][0])); - item->bbox.y0 = static_cast<NR::ICoord>(floor((*boundingbox)[1][0])); - item->bbox.x1 = static_cast<NR::ICoord>(ceil ((*boundingbox)[0][1])); - item->bbox.y1 = static_cast<NR::ICoord>(ceil ((*boundingbox)[1][1])); - - item->render_opacity = TRUE; - if ( shape->_fill.paint.type() == NRArenaShape::Paint::SERVER ) { - if (gc && gc->parent) { - shape->fill_painter = sp_paint_server_painter_new(shape->_fill.paint.server(), - gc->transform, gc->parent->transform, - &shape->paintbox); - } - item->render_opacity = FALSE; - } - if ( shape->_stroke.paint.type() == NRArenaShape::Paint::SERVER ) { - if (gc && gc->parent) { - shape->stroke_painter = sp_paint_server_painter_new(shape->_stroke.paint.server(), - gc->transform, gc->parent->transform, - &shape->paintbox); - } - item->render_opacity = FALSE; - } - if ( (shape->_fill.paint.type() != NRArenaShape::Paint::NONE && - shape->_stroke.paint.type() != NRArenaShape::Paint::NONE) - || (shape->markers) - ) - { - // don't merge item opacity with paint opacity if there is a stroke on the fill, or markers on stroke - item->render_opacity = FALSE; } if (beststate & NR_ARENA_ITEM_STATE_BBOX) { @@ -402,328 +305,9 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g return NR_ARENA_ITEM_STATE_ALL; } -int matrix_is_isometry(Geom::Affine p) { - Geom::Affine tp; - // transposition - tp[0]=p[0]; - tp[1]=p[2]; - tp[2]=p[1]; - tp[3]=p[3]; - for (int i = 4; i < 6; i++) // shut valgrind up :) - tp[i] = p[i] = 0; - Geom::Affine isom = tp*p; // A^T * A = adjunct? - // Is the adjunct nearly an identity function? - if (isom.isTranslation(0.01)) { - // the transformation is an isometry -> no need to recompute - // the uncrossed polygon - if ( p.det() < 0 ) - return -1; - else - return 1; - } - return 0; -} - -static bool is_inner_area(NRRectL const &outer, NRRectL const &inner) { - return (outer.x0 <= inner.x0 && outer.y0 <= inner.y0 && outer.x1 >= inner.x1 && outer.y1 >= inner.y1); -} - -/* returns true if the pathvector has a region that needs fill. - * is for optimizing purposes, so should be fast and can falsely return true. - * CANNOT falsely return false. */ -static bool has_inner_area(Geom::PathVector const & pv) { - // return false for the cases where there is surely no region to be filled - if (pv.empty()) - return false; - - if ( (pv.size() == 1) && (pv.front().size() <= 1) ) { - // vector has only one path with only one segment, see if that's a non-curve segment: that would mean no internal region - if ( is_straight_curve(pv.front().front()) ) - { - return false; - } - } - - return true; //too costly to see if it has region to be filled, so return true. -} - -/** force_shape is used for clipping paths, when we need the shape for clipping even if it's not filled */ -void -nr_arena_shape_update_fill(NRArenaShape *shape, NRGC *gc, NRRectL *area, bool force_shape) -{ - if ((shape->_fill.paint.type() != NRArenaShape::Paint::NONE || force_shape) && - has_inner_area(shape->curve->get_pathvector()) ) { - - Geom::Affine cached_to_new = Geom::identity(); - int isometry = 0; - if ( shape->cached_fill ) { - if (shape->cached_fctm == gc->transform) { - isometry = 2; // identity - } else { - cached_to_new = shape->cached_fctm.inverse() * gc->transform; - isometry = matrix_is_isometry(cached_to_new); - } - if (0 != isometry && !is_inner_area(shape->cached_farea, *area)) - isometry = 0; - } - if ( isometry == 0 ) { - if ( shape->cached_fill == NULL ) shape->cached_fill=new Shape; - shape->cached_fill->Reset(); - - Path* thePath=new Path; - Shape* theShape=new Shape; - { - Geom::Affine tempMat(gc->transform); - thePath->LoadPathVector(shape->curve->get_pathvector(), tempMat, true); - } - - if (is_inner_area(*area, NR_ARENA_ITEM(shape)->bbox)) { - thePath->Convert(1.0); - shape->cached_fpartialy = false; - } else { - thePath->Convert(area, 1.0); - shape->cached_fpartialy = true; - } - - thePath->Fill(theShape, 0); - - if ( shape->_fill.rule == NRArenaShape::EVEN_ODD ) { - shape->cached_fill->ConvertToShape(theShape, fill_oddEven); - // alternatively, this speeds up rendering of oddeven shapes but disables AA :( - //shape->cached_fill->Copy(theShape); - } else { - shape->cached_fill->ConvertToShape(theShape, fill_nonZero); - } - shape->cached_fctm=gc->transform; - shape->cached_farea = *area; - delete theShape; - delete thePath; - if ( shape->fill_shp == NULL ) - shape->fill_shp = new Shape; - - shape->fill_shp->Copy(shape->cached_fill); - - } else if ( 2 == isometry ) { - if ( shape->fill_shp == NULL ) { - shape->fill_shp = new Shape; - shape->fill_shp->Copy(shape->cached_fill); - } - } else { - - if ( shape->fill_shp == NULL ) - shape->fill_shp = new Shape; - - shape->fill_shp->Reset(shape->cached_fill->numberOfPoints(), - shape->cached_fill->numberOfEdges()); - for (int i = 0; i < shape->cached_fill->numberOfPoints(); i++) - shape->fill_shp->AddPoint(to_2geom(shape->cached_fill->getPoint(i).x) * cached_to_new); - if ( isometry == 1 ) { - for (int i = 0; i < shape->cached_fill->numberOfEdges(); i++) - shape->fill_shp->AddEdge(shape->cached_fill->getEdge(i).st, - shape->cached_fill->getEdge(i).en); - } else if ( isometry == -1 ) { // need to flip poly. - for (int i = 0; i < shape->cached_fill->numberOfEdges(); i++) - shape->fill_shp->AddEdge(shape->cached_fill->getEdge(i).en, - shape->cached_fill->getEdge(i).st); - } - shape->fill_shp->ForceToPolygon(); - shape->fill_shp->needPointsSorting(); - shape->fill_shp->needEdgesSorting(); - } - shape->delayed_shp |= shape->cached_fpartialy; - } -} - -void -nr_arena_shape_update_stroke(NRArenaShape *shape,NRGC* gc, NRRectL *area) -{ - SPStyle* style = shape->style; - - float const scale = gc->transform.descrim(); - - bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - - if (outline) { - // cairo does not need the livarot path for rendering - return; - } - - // after switching normal stroke rendering to cairo too, optimize this: lower tolerance, disregard dashes - // (since it will only be used for picking, not for rendering) - - if (outline || - ((shape->_stroke.paint.type() != NRArenaShape::Paint::NONE) && - ( fabs(shape->_stroke.width * scale) > 0.01 ))) { // sinon c'est 0=oon veut pas de bord - - float style_width = MAX(0.125, shape->_stroke.width * scale); - float width; - if (outline) { - width = 0.5; // 1 pixel wide, independent of zoom - } else { - width = style_width; - } - - Geom::Affine cached_to_new = Geom::identity(); - - int isometry = 0; - if ( shape->cached_stroke ) { - if (shape->cached_sctm == gc->transform) { - isometry = 2; // identity - } else { - cached_to_new = shape->cached_sctm.inverse() * gc->transform; - isometry = matrix_is_isometry(cached_to_new); - } - if (0 != isometry && !is_inner_area(shape->cached_sarea, *area)) - isometry = 0; - if (0 != isometry && width != shape->cached_width) { - // if this happens without setting style, we have just switched to outline or back - isometry = 0; - } - } - - if ( isometry == 0 ) { - if ( shape->cached_stroke == NULL ) shape->cached_stroke=new Shape; - shape->cached_stroke->Reset(); - Path* thePath = new Path; - Shape* theShape = new Shape; - { - Geom::Affine tempMat( gc->transform ); - thePath->LoadPathVector(shape->curve->get_pathvector(), tempMat, true); - } - - // add some padding to the rendering area, so clipped path does not go into a render area - NRRectL padded_area = *area; - padded_area.x0 -= (NR::ICoord)width; - padded_area.x1 += (NR::ICoord)width; - padded_area.y0 -= (NR::ICoord)width; - padded_area.y1 += (NR::ICoord)width; - if ((style->stroke_dash.n_dash && !outline) || is_inner_area(padded_area, NR_ARENA_ITEM(shape)->bbox)) { - thePath->Convert((outline) ? 4.0 : 1.0); - shape->cached_spartialy = false; - } - else { - thePath->Convert(&padded_area, (outline) ? 4.0 : 1.0); - shape->cached_spartialy = true; - } - - if (style->stroke_dash.n_dash && !outline) { - thePath->DashPolylineFromStyle(style, scale, 1.0); - } - - ButtType butt=butt_straight; - switch (shape->_stroke.cap) { - case NRArenaShape::BUTT_CAP: - butt = butt_straight; - break; - case NRArenaShape::ROUND_CAP: - butt = butt_round; - break; - case NRArenaShape::SQUARE_CAP: - butt = butt_square; - break; - } - JoinType join=join_straight; - switch (shape->_stroke.join) { - case NRArenaShape::MITRE_JOIN: - join = join_pointy; - break; - case NRArenaShape::ROUND_JOIN: - join = join_round; - break; - case NRArenaShape::BEVEL_JOIN: - join = join_straight; - break; - } - - if (outline) { - butt = butt_straight; - join = join_straight; - } - - thePath->Stroke(theShape, false, 0.5*width, join, butt, - 0.5*width*shape->_stroke.mitre_limit); - - - if (outline) { - // speeds it up, but uses evenodd for the stroke shape (which does not matter for 1-pixel wide outline) - shape->cached_stroke->Copy(theShape); - } else { - shape->cached_stroke->ConvertToShape(theShape, fill_nonZero); - } - - shape->cached_width = width; - - shape->cached_sctm=gc->transform; - shape->cached_sarea = *area; - delete thePath; - delete theShape; - if ( shape->stroke_shp == NULL ) shape->stroke_shp=new Shape; - - shape->stroke_shp->Copy(shape->cached_stroke); - - } else if ( 2 == isometry ) { - if ( shape->stroke_shp == NULL ) { - shape->stroke_shp=new Shape; - shape->stroke_shp->Copy(shape->cached_stroke); - } - } else { - if ( shape->stroke_shp == NULL ) - shape->stroke_shp=new Shape; - shape->stroke_shp->Reset(shape->cached_stroke->numberOfPoints(), shape->cached_stroke->numberOfEdges()); - for (int i = 0; i < shape->cached_stroke->numberOfPoints(); i++) - shape->stroke_shp->AddPoint(to_2geom(shape->cached_stroke->getPoint(i).x) * cached_to_new); - if ( isometry == 1 ) { - for (int i = 0; i < shape->cached_stroke->numberOfEdges(); i++) - shape->stroke_shp->AddEdge(shape->cached_stroke->getEdge(i).st, - shape->cached_stroke->getEdge(i).en); - } else if ( isometry == -1 ) { - for (int i = 0; i < shape->cached_stroke->numberOfEdges(); i++) - shape->stroke_shp->AddEdge(shape->cached_stroke->getEdge(i).en, - shape->cached_stroke->getEdge(i).st); - } - shape->stroke_shp->ForceToPolygon(); - shape->stroke_shp->needPointsSorting(); - shape->stroke_shp->needEdgesSorting(); - } - shape->delayed_shp |= shape->cached_spartialy; - } -} - - -void -nr_arena_shape_add_bboxes(NRArenaShape* shape, Geom::OptRect &bbox) -{ - /* TODO: are these two if's mutually exclusive? ( i.e. "shape->stroke_shp <=> !shape->fill_shp" ) - * if so, then this can be written much more compact ! */ - - if ( shape->stroke_shp ) { - Shape *larger = shape->stroke_shp; - larger->CalcBBox(); - larger->leftX = floor(larger->leftX); - larger->rightX = ceil(larger->rightX); - larger->topY = floor(larger->topY); - larger->bottomY = ceil(larger->bottomY); - Geom::Rect stroke_bbox( Geom::Interval(larger->leftX, larger->rightX), - Geom::Interval(larger->topY, larger->bottomY) ); - bbox.unionWith(stroke_bbox); - } - - if ( shape->fill_shp ) { - Shape *larger = shape->fill_shp; - larger->CalcBBox(); - larger->leftX = floor(larger->leftX); - larger->rightX = ceil(larger->rightX); - larger->topY = floor(larger->topY); - larger->bottomY = ceil(larger->bottomY); - Geom::Rect fill_bbox( Geom::Interval(larger->leftX, larger->rightX), - Geom::Interval(larger->topY, larger->bottomY) ); - bbox.unionWith(fill_bbox); - } -} - // cairo outline rendering: static unsigned int -cairo_arena_shape_render_outline(cairo_t *ct, NRArenaItem *item, Geom::OptRect area) +cairo_arena_shape_render_outline(cairo_t *ct, NRArenaItem *item, Geom::OptRect /*area*/) { NRArenaShape *shape = NR_ARENA_SHAPE(item); @@ -731,107 +315,21 @@ cairo_arena_shape_render_outline(cairo_t *ct, NRArenaItem *item, Geom::OptRect a return item->state; guint32 rgba = NR_ARENA_ITEM(shape)->arena->outlinecolor; - // FIXME: we use RGBA buffers but cairo writes BGRA (on i386), so we must cheat - // by setting color channels in the "wrong" order - cairo_set_source_rgba(ct, SP_RGBA32_B_F(rgba), SP_RGBA32_G_F(rgba), SP_RGBA32_R_F(rgba), SP_RGBA32_A_F(rgba)); + cairo_save(ct); + ink_cairo_transform(ct, shape->ctm); + feed_pathvector_to_cairo (ct, shape->curve->get_pathvector()); + cairo_restore(ct); + cairo_save(ct); + ink_cairo_set_source_rgba32(ct, rgba); cairo_set_line_width(ct, 0.5); cairo_set_tolerance(ct, 1.25); // low quality, but good enough for outline mode - cairo_new_path(ct); - - feed_pathvector_to_cairo (ct, shape->curve->get_pathvector(), shape->ctm, area, true, 0); - cairo_stroke(ct); + cairo_restore(ct); return item->state; } -// cairo stroke rendering (flat color only so far!): -// works on canvas, but wrongs the colors in nonpremul buffers: icons and png export -// (need to switch them to premul before this can be enabled) -void -cairo_arena_shape_render_stroke(NRArenaItem *item, NRRectL *area, NRPixBlock *pb) -{ - NRArenaShape *shape = NR_ARENA_SHAPE(item); - SPStyle const *style = shape->style; - - float const scale = shape->ctm.descrim(); - - if (fabs(shape->_stroke.width * scale) < 0.01) - return; - - cairo_t *ct = nr_create_cairo_context (area, pb); - - if (!ct) - return; - - guint32 rgba; - if ( item->render_opacity ) { - rgba = shape->_stroke.paint.color().toRGBA32( shape->_stroke.opacity * - SP_SCALE24_TO_FLOAT(style->opacity.value) ); - } else { - rgba = shape->_stroke.paint.color().toRGBA32( shape->_stroke.opacity ); - } - - // FIXME: we use RGBA buffers but cairo writes BGRA (on i386), so we must cheat - // by setting color channels in the "wrong" order - cairo_set_source_rgba(ct, SP_RGBA32_B_F(rgba), SP_RGBA32_G_F(rgba), SP_RGBA32_R_F(rgba), SP_RGBA32_A_F(rgba)); - - float style_width = MAX(0.125, shape->_stroke.width * scale); - cairo_set_line_width(ct, style_width); - - switch (shape->_stroke.cap) { - case NRArenaShape::BUTT_CAP: - cairo_set_line_cap(ct, CAIRO_LINE_CAP_BUTT); - break; - case NRArenaShape::ROUND_CAP: - cairo_set_line_cap(ct, CAIRO_LINE_CAP_ROUND); - break; - case NRArenaShape::SQUARE_CAP: - cairo_set_line_cap(ct, CAIRO_LINE_CAP_SQUARE); - break; - } - switch (shape->_stroke.join) { - case NRArenaShape::MITRE_JOIN: - cairo_set_line_join(ct, CAIRO_LINE_JOIN_MITER); - break; - case NRArenaShape::ROUND_JOIN: - cairo_set_line_join(ct, CAIRO_LINE_JOIN_ROUND); - break; - case NRArenaShape::BEVEL_JOIN: - cairo_set_line_join(ct, CAIRO_LINE_JOIN_BEVEL); - break; - } - - cairo_set_miter_limit (ct, style->stroke_miterlimit.value); - - if (style->stroke_dash.n_dash) { - NRVpathDash dash; - dash.offset = style->stroke_dash.offset * scale; - dash.n_dash = style->stroke_dash.n_dash; - dash.dash = g_new(double, dash.n_dash); - for (int i = 0; i < dash.n_dash; i++) { - dash.dash[i] = style->stroke_dash.dash[i] * scale; - } - cairo_set_dash (ct, dash.dash, dash.n_dash, dash.offset); - g_free(dash.dash); - } - - cairo_set_tolerance(ct, 0.1); - cairo_new_path(ct); - - feed_pathvector_to_cairo (ct, shape->curve->get_pathvector(), shape->ctm, to_2geom(area->upgrade()), true, style_width); - - cairo_stroke(ct); - - cairo_surface_t *cst = cairo_get_target(ct); - cairo_destroy (ct); - cairo_surface_finish (cst); - cairo_surface_destroy (cst); - - pb->empty = FALSE; -} - /** * Renders the item. Markers are just composed into the parent buffer. */ @@ -842,150 +340,51 @@ nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock if (!shape->curve) return item->state; if (!shape->style) return item->state; + if (!ct) return item->state; + + // skip if not within bounding box + if (!nr_rect_l_test_intersect_ptr(area, &item->bbox)) { + return item->state; + } bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - bool print_colors_preview = (NR_ARENA_ITEM(shape)->arena->colorrendermode == Inkscape::COLORRENDERMODE_PRINT_COLORS_PREVIEW); - bool grayscale = (NR_ARENA_ITEM(shape)->arena->colorrendermode == Inkscape::COLORRENDERMODE_GRAYSCALE); if (outline) { // cairo outline rendering - pb->empty = FALSE; - unsigned int ret = cairo_arena_shape_render_outline (ct, item, to_2geom((&pb->area)->upgrade())); + NRRect temp(area->x0, area->y0, area->x1, area->y1); + unsigned int ret = cairo_arena_shape_render_outline (ct, item, temp.upgrade_2geom()); if (ret & NR_ARENA_ITEM_STATE_INVALID) return ret; } else { - - if ( shape->delayed_shp ) { - if ( nr_rect_l_test_intersect_ptr(area, &item->bbox) ) { - NRGC tempGC(NULL); - tempGC.transform=shape->ctm; - shape->delayed_shp = false; - nr_arena_shape_update_stroke(shape,&tempGC,&pb->visible_area); - nr_arena_shape_update_fill(shape,&tempGC,&pb->visible_area); -/* NRRect bbox; - bbox.x0 = bbox.y0 = bbox.x1 = bbox.y1 = 0.0; - nr_arena_shape_add_bboxes(shape,bbox); - item->bbox.x0 = (gint32)(bbox.x0 - 1.0F); - item->bbox.y0 = (gint32)(bbox.y0 - 1.0F); - item->bbox.x1 = (gint32)(bbox.x1 + 1.0F); - item->bbox.y1 = (gint32)(bbox.y1 + 1.0F); - shape->approx_bbox=item->bbox;*/ - } else { - return item->state; - } - } - - SPStyle const *style = shape->style; - - if (shape->fill_shp) { - NRPixBlock m; - guint32 rgba; - - nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE); - - // if memory allocation failed, abort render - if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) { - nr_pixblock_release (&m); - return (item->state); - } - - m.visible_area = pb->visible_area; - nr_pixblock_render_shape_mask_or(m,shape->fill_shp); - m.empty = FALSE; - - if (shape->_fill.paint.type() == NRArenaShape::Paint::NONE) { - // do not render fill in any way - } else if (shape->_fill.paint.type() == NRArenaShape::Paint::COLOR) { - - const SPColor* fill_color = &shape->_fill.paint.color(); - if ( item->render_opacity ) { - rgba = fill_color->toRGBA32( shape->_fill.opacity * - SP_SCALE24_TO_FLOAT(style->opacity.value) ); - } else { - rgba = fill_color->toRGBA32( shape->_fill.opacity ); + bool has_stroke, has_fill; + // we assume the context has no path + cairo_save(ct); + ink_cairo_transform(ct, shape->ctm); + + // update fill and stroke paints. + // this cannot be done during nr_arena_shape_update, because we need a Cairo context + // to render svg:pattern + has_fill = shape->nrstyle.prepareFill(ct, &shape->paintbox); + has_stroke = shape->nrstyle.prepareStroke(ct, &shape->paintbox); + has_stroke &= (shape->nrstyle.stroke_width != 0); + + if (has_fill || has_stroke) { + // TODO: remove segments outside of bbox when no dashes present + feed_pathvector_to_cairo(ct, shape->curve->get_pathvector()); + if (has_fill) { + shape->nrstyle.applyFill(ct); + cairo_fill_preserve(ct); } - - if (print_colors_preview) { - nr_arena_separate_color_plates(&rgba); - } else if (grayscale) { - rgba = Grayscale::process(rgba); - } - - nr_blit_pixblock_mask_rgba32(pb, &m, rgba); - pb->empty = FALSE; - } else if (shape->_fill.paint.type() == NRArenaShape::Paint::SERVER) { - if (shape->fill_painter) { - nr_arena_render_paintserver_fill(pb, area, shape->fill_painter, shape->_fill.opacity, &m); + if (has_stroke) { + shape->nrstyle.applyStroke(ct); + cairo_stroke_preserve(ct); } - } - - nr_pixblock_release(&m); + cairo_new_path(ct); // clear path + } // has fill or stroke pattern + cairo_restore(ct); } - if (shape->stroke_shp && shape->_stroke.paint.type() == NRArenaShape::Paint::COLOR) { - - // cairo_arena_shape_render_stroke(item, area, pb); - - guint32 rgba; - NRPixBlock m; - - nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE); - - // if memory allocation failed, abort render - if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) { - nr_pixblock_release (&m); - return (item->state); - } - - m.visible_area = pb->visible_area; - nr_pixblock_render_shape_mask_or(m, shape->stroke_shp); - m.empty = FALSE; - - const SPColor* stroke_color = &shape->_stroke.paint.color(); - if ( item->render_opacity ) { - rgba = stroke_color->toRGBA32( shape->_stroke.opacity * - SP_SCALE24_TO_FLOAT(style->opacity.value) ); - } else { - rgba = stroke_color->toRGBA32( shape->_stroke.opacity ); - } - - if (print_colors_preview) { - nr_arena_separate_color_plates(&rgba); - } else if (grayscale) { - rgba = Grayscale::process(rgba); - } - - nr_blit_pixblock_mask_rgba32(pb, &m, rgba); - pb->empty = FALSE; - - nr_pixblock_release(&m); - - } else if (shape->stroke_shp && shape->_stroke.paint.type() == NRArenaShape::Paint::SERVER) { - - NRPixBlock m; - - nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE); - - // if memory allocation failed, abort render - if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) { - nr_pixblock_release (&m); - return (item->state); - } - - m.visible_area = pb->visible_area; - nr_pixblock_render_shape_mask_or(m, shape->stroke_shp); - m.empty = FALSE; - - if (shape->stroke_painter) { - nr_arena_render_paintserver_fill(pb, area, shape->stroke_painter, shape->_stroke.opacity, &m); - } - - nr_pixblock_release(&m); - } - - } // non-cairo non-outline branch - - /* Render markers into parent buffer */ + // marker rendering for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) { unsigned int ret = nr_arena_item_invoke_render(ct, child, area, pb, flags); if (ret & NR_ARENA_ITEM_STATE_INVALID) return ret; @@ -995,88 +394,18 @@ nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock } -// cairo clipping: this basically works except for the stride-must-be-divisible-by-4 cairo bug; -// reenable this when the bug is fixed and remove the rest of this function -// TODO -#if defined(DEADCODE) && !defined(DEADCODE) -static guint -cairo_arena_shape_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb) -{ - NRArenaShape *shape = NR_ARENA_SHAPE(item); - if (!shape->curve) return item->state; - - cairo_t *ct = nr_create_cairo_context (area, pb); - - if (!ct) - return item->state; - - cairo_set_source_rgba(ct, 0, 0, 0, 1); - - cairo_new_path(ct); - - feed_pathvector_to_cairo (ct, shape->curve->get_pathvector(), shape->ctm, (area)->upgrade(), false, 0); - - cairo_fill(ct); - - cairo_surface_t *cst = cairo_get_target(ct); - cairo_destroy (ct); - cairo_surface_finish (cst); - cairo_surface_destroy (cst); - - pb->empty = FALSE; - - return item->state; -} -#endif //defined(DEADCODE) && !defined(DEADCODE) - - static guint -nr_arena_shape_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb) +nr_arena_shape_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area) { - //return cairo_arena_shape_clip(item, area, pb); - + // NOTE: for now this is incorrect, because it doesn't honor clip-rule, + // and will be incorrect for nested clipping paths. NRArenaShape *shape = NR_ARENA_SHAPE(item); if (!shape->curve) return item->state; - if ( shape->delayed_shp || shape->fill_shp == NULL) { // we need a fill shape no matter what - if ( nr_rect_l_test_intersect_ptr(area, &item->bbox) ) { - NRGC tempGC(NULL); - tempGC.transform=shape->ctm; - shape->delayed_shp = false; - nr_arena_shape_update_fill(shape, &tempGC, &pb->visible_area, true); - } else { - return item->state; - } - } - - if ( shape->fill_shp ) { - NRPixBlock m; - - /* fixme: We can OR in one step (Lauris) */ - nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE); - - // if memory allocation failed, abort - if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) { - nr_pixblock_release (&m); - return (item->state); - } - - m.visible_area = pb->visible_area; - nr_pixblock_render_shape_mask_or(m,shape->fill_shp); - - for (int y = area->y0; y < area->y1; y++) { - unsigned char *s, *d; - s = NR_PIXBLOCK_PX(&m) + (y - area->y0) * m.rs; - d = NR_PIXBLOCK_PX(pb) + (y - area->y0) * pb->rs; - for (int x = area->x0; x < area->x1; x++) { - *d = NR_COMPOSEA_111(*s, *d); - d ++; - s ++; - } - } - nr_pixblock_release(&m); - pb->empty = FALSE; - } + cairo_save(ct); + ink_cairo_transform(ct, shape->ctm); + feed_pathvector_to_cairo(ct, shape->curve->get_pathvector()); + cairo_restore(ct); return item->state; } @@ -1107,17 +436,17 @@ nr_arena_shape_pick(NRArenaItem *item, Geom::Point p, double delta, unsigned int double width; if (outline) { width = 0.5; - } else if (shape->_stroke.paint.type() != NRArenaShape::Paint::NONE && shape->_stroke.opacity > 1e-3) { + } else if (shape->nrstyle.stroke.type != NRStyle::PAINT_NONE && shape->nrstyle.stroke.opacity > 1e-3) { float const scale = shape->ctm.descrim(); - width = MAX(0.125, shape->_stroke.width * scale) / 2; + width = MAX(0.125, shape->nrstyle.stroke_width * scale) / 2; } else { width = 0; } - double dist = NR_HUGE; + double dist = Geom::infinity(); int wind = 0; - bool needfill = (shape->_fill.paint.type() != NRArenaShape::Paint::NONE - && shape->_fill.opacity > 1e-3 && !outline); + bool needfill = (shape->nrstyle.fill.type != NRStyle::PAINT_NONE + && shape->nrstyle.fill.opacity > 1e-3 && !outline); if (item->arena->canvasarena) { Geom::Rect viewbox = item->arena->canvasarena->item.canvas->getViewbox(); @@ -1184,18 +513,6 @@ void nr_arena_shape_set_path(NRArenaShape *shape, SPCurve *curve,bool justTrans) g_return_if_fail(shape != NULL); g_return_if_fail(NR_IS_ARENA_SHAPE(shape)); - if ( justTrans == false ) { - // dirty cached versions - if ( shape->cached_fill ) { - delete shape->cached_fill; - shape->cached_fill=NULL; - } - if ( shape->cached_stroke ) { - delete shape->cached_stroke; - shape->cached_stroke=NULL; - } - } - nr_arena_item_request_render(NR_ARENA_ITEM(shape)); if (shape->curve) { @@ -1211,61 +528,6 @@ void nr_arena_shape_set_path(NRArenaShape *shape, SPCurve *curve,bool justTrans) nr_arena_item_request_update(NR_ARENA_ITEM(shape), NR_ARENA_ITEM_STATE_ALL, FALSE); } -void NRArenaShape::setFill(SPPaintServer *server) { - _fill.paint.set(server); - _invalidateCachedFill(); -} - -void NRArenaShape::setFill(SPColor const &color) { - _fill.paint.set(color); - _invalidateCachedFill(); -} - -void NRArenaShape::setFillOpacity(double opacity) { - _fill.opacity = opacity; - _invalidateCachedFill(); -} - -void NRArenaShape::setFillRule(NRArenaShape::FillRule rule) { - _fill.rule = rule; - _invalidateCachedFill(); -} - -void NRArenaShape::setStroke(SPPaintServer *server) { - _stroke.paint.set(server); - _invalidateCachedStroke(); -} - -void NRArenaShape::setStroke(SPColor const &color) { - _stroke.paint.set(color); - _invalidateCachedStroke(); -} - -void NRArenaShape::setStrokeOpacity(double opacity) { - _stroke.opacity = opacity; - _invalidateCachedStroke(); -} - -void NRArenaShape::setStrokeWidth(double width) { - _stroke.width = width; - _invalidateCachedStroke(); -} - -void NRArenaShape::setMitreLimit(double limit) { - _stroke.mitre_limit = limit; - _invalidateCachedStroke(); -} - -void NRArenaShape::setLineCap(NRArenaShape::CapType cap) { - _stroke.cap = cap; - _invalidateCachedStroke(); -} - -void NRArenaShape::setLineJoin(NRArenaShape::JoinType join) { - _stroke.join = join; - _invalidateCachedStroke(); -} - /** nr_arena_shape_set_style * * Unrefs any existing style and ref's to the given one, then requests an update of the arena @@ -1275,81 +537,13 @@ nr_arena_shape_set_style(NRArenaShape *shape, SPStyle *style) { g_return_if_fail(shape != NULL); g_return_if_fail(NR_IS_ARENA_SHAPE(shape)); + g_return_if_fail(style != NULL); - if (style) sp_style_ref(style); + sp_style_ref(style); if (shape->style) sp_style_unref(shape->style); shape->style = style; - if ( style->fill.isPaintserver() ) { - shape->setFill(style->getFillPaintServer()); - } else if ( style->fill.isColor() ) { - shape->setFill(style->fill.value.color); - } else if ( style->fill.isNone() ) { - shape->setFill(NULL); - } else { - g_assert_not_reached(); - } - shape->setFillOpacity(SP_SCALE24_TO_FLOAT(style->fill_opacity.value)); - switch (style->fill_rule.computed) { - case SP_WIND_RULE_EVENODD: { - shape->setFillRule(NRArenaShape::EVEN_ODD); - break; - } - case SP_WIND_RULE_NONZERO: { - shape->setFillRule(NRArenaShape::NONZERO); - break; - } - default: { - g_assert_not_reached(); - } - } - - if ( style->stroke.isPaintserver() ) { - shape->setStroke(style->getStrokePaintServer()); - } else if ( style->stroke.isColor() ) { - shape->setStroke(style->stroke.value.color); - } else if ( style->stroke.isNone() ) { - shape->setStroke(NULL); - } else { - g_assert_not_reached(); - } - shape->setStrokeWidth(style->stroke_width.computed); - shape->setStrokeOpacity(SP_SCALE24_TO_FLOAT(style->stroke_opacity.value)); - switch (style->stroke_linecap.computed) { - case SP_STROKE_LINECAP_ROUND: { - shape->setLineCap(NRArenaShape::ROUND_CAP); - break; - } - case SP_STROKE_LINECAP_SQUARE: { - shape->setLineCap(NRArenaShape::SQUARE_CAP); - break; - } - case SP_STROKE_LINECAP_BUTT: { - shape->setLineCap(NRArenaShape::BUTT_CAP); - break; - } - default: { - g_assert_not_reached(); - } - } - switch (style->stroke_linejoin.computed) { - case SP_STROKE_LINEJOIN_ROUND: { - shape->setLineJoin(NRArenaShape::ROUND_JOIN); - break; - } - case SP_STROKE_LINEJOIN_BEVEL: { - shape->setLineJoin(NRArenaShape::BEVEL_JOIN); - break; - } - case SP_STROKE_LINEJOIN_MITER: { - shape->setLineJoin(NRArenaShape::MITRE_JOIN); - break; - } - default: { - g_assert_not_reached(); - } - } - shape->setMitreLimit(style->stroke_miterlimit.value); + shape->nrstyle.set(style); //if shape has a filter if (style->filter.set && style->getFilter()) { @@ -1395,118 +589,6 @@ void NRArenaShape::setPaintBox(Geom::Rect const &pbox) nr_arena_item_request_update(this, NR_ARENA_ITEM_STATE_ALL, FALSE); } -static void -shape_run_A8_OR(raster_info &dest,void */*data*/,int st,float vst,int en,float ven) -{ - if ( st >= en ) return; - if ( vst < 0 ) vst=0; - if ( vst > 1 ) vst=1; - if ( ven < 0 ) ven=0; - if ( ven > 1 ) ven=1; - float sv=vst; - float dv=ven-vst; - int len=en-st; - unsigned char* d=(unsigned char*)dest.buffer; - d+=(st-dest.startPix); - if ( fabs(dv) < 0.001 ) { - if ( vst > 0.999 ) { - /* Simple copy */ - while (len > 0) { - d[0] = 255; - d += 1; - len -= 1; - } - } else { - sv*=256; - unsigned int c0_24=(int)sv; - c0_24&=0xFF; - while (len > 0) { - /* Draw */ - d[0] = NR_COMPOSEA_111(c0_24,d[0]); - d += 1; - len -= 1; - } - } - } else { - if ( en <= st+1 ) { - sv=0.5*(vst+ven); - sv*=256; - unsigned int c0_24=(int)sv; - c0_24&=0xFF; - /* Draw */ - d[0] = NR_COMPOSEA_111(c0_24,d[0]); - } else { - dv/=len; - sv+=0.5*dv; // correction trapezoidale - sv*=16777216; - dv*=16777216; - int c0_24 = static_cast<int>(CLAMP(sv, 0, 16777216)); - int s0_24 = static_cast<int>(dv); - while (len > 0) { - unsigned int ca; - /* Draw */ - ca = c0_24 >> 16; - if ( ca > 255 ) ca=255; - d[0] = NR_COMPOSEA_111(ca,d[0]); - d += 1; - c0_24 += s0_24; - c0_24 = CLAMP(c0_24, 0, 16777216); - len -= 1; - } - } - } -} - -void nr_pixblock_render_shape_mask_or(NRPixBlock &m,Shape* theS) -{ - theS->CalcBBox(); - float l = theS->leftX, r = theS->rightX, t = theS->topY, b = theS->bottomY; - int il,ir,it,ib; - il=(int)floor(l); - ir=(int)ceil(r); - it=(int)floor(t); - ib=(int)ceil(b); - - if ( il >= m.area.x1 || ir <= m.area.x0 || it >= m.area.y1 || ib <= m.area.y0 ) return; - if ( il < m.area.x0 ) il=m.area.x0; - if ( it < m.area.y0 ) it=m.area.y0; - if ( ir > m.area.x1 ) ir=m.area.x1; - if ( ib > m.area.y1 ) ib=m.area.y1; - - /* This is the FloatLigne version. See svn (prior to Apr 2006) for versions using BitLigne or direct BitLigne. */ - int curPt; - float curY; - theS->BeginQuickRaster(curY, curPt); - - FloatLigne *theI = new FloatLigne(); - IntLigne *theIL = new IntLigne(); - - theS->DirectQuickScan(curY, curPt, (float) it, true, 1.0); - - char *mdata = (char*)m.data.px; - if ( m.size == NR_PIXBLOCK_SIZE_TINY ) mdata=(char*)m.data.p; - uint32_t *ligStart = ((uint32_t*)(mdata + ((il - m.area.x0) + m.rs * (it - m.area.y0)))); - for (int y = it; y < ib; y++) { - theI->Reset(); - theS->QuickScan(curY, curPt, ((float)(y+1)), theI, 1.0); - theI->Flatten(); - theIL->Copy(theI); - - raster_info dest; - dest.startPix=il; - dest.endPix=ir; - dest.sth=il; - dest.stv=y; - dest.buffer=ligStart; - theIL->Raster(dest, NULL, shape_run_A8_OR); - ligStart=((uint32_t*)(((char*)ligStart)+m.rs)); - } - theS->EndQuickRaster(); - delete theI; - delete theIL; -} - - /* Local Variables: mode:c++ diff --git a/src/display/nr-arena-shape.h b/src/display/nr-arena-shape.h index e00993901..2ee0d24c8 100644 --- a/src/display/nr-arena-shape.h +++ b/src/display/nr-arena-shape.h @@ -17,133 +17,30 @@ #define NR_ARENA_SHAPE(obj) (NR_CHECK_INSTANCE_CAST ((obj), NR_TYPE_ARENA_SHAPE, NRArenaShape)) #define NR_IS_ARENA_SHAPE(obj) (NR_CHECK_INSTANCE_TYPE ((obj), NR_TYPE_ARENA_SHAPE)) -#include "display/canvas-bpath.h" +#include <cairo.h> +#include "display/display-forward.h" #include "forward.h" -#include "sp-paint-server.h" #include "nr-arena-item.h" - -#include "../color.h" - -#include "../livarot/Shape.h" +#include "nr-style.h" NRType nr_arena_shape_get_type (void); struct NRArenaShape : public NRArenaItem { - class Paint { - public: - enum Type { - NONE, - COLOR, - SERVER - }; - - Paint() : _type(NONE), _color(0), _server(NULL) {} - Paint(Paint const &p) { _assign(p); } - virtual ~Paint() { clear(); } - - Type type() const { return _type; } - SPPaintServer *server() const { return _server; } - SPColor const &color() const { return _color; } - - Paint &operator=(Paint const &p) { - set(p); - return *this; - } - - void set(Paint const &p) { - clear(); - _assign(p); - } - void set(SPColor const &color) { - clear(); - _type = COLOR; - _color = color; - } - void set(SPPaintServer *server) { - clear(); - if (server) { - _type = SERVER; - _server = server; - sp_object_ref(_server, NULL); - } - } - void clear() { - if ( _type == SERVER ) { - sp_object_unref(_server, NULL); - _server = NULL; - } - _type = NONE; - } - - private: - Type _type; - SPColor _color; - SPPaintServer *_server; - - void _assign(Paint const &p) { - _type = p._type; - _server = p._server; - _color = p._color; - if (_server) { - sp_object_ref(_server, NULL); - } - } - }; - - enum FillRule { - EVEN_ODD, - NONZERO - }; - - enum CapType { - ROUND_CAP, - SQUARE_CAP, - BUTT_CAP - }; - - enum JoinType { - ROUND_JOIN, - BEVEL_JOIN, - MITRE_JOIN - }; - /* Shape data */ SPCurve *curve; SPStyle *style; + NRStyle nrstyle; NRRect paintbox; - /* State data */ - Geom::Affine ctm; - - SPPainter *fill_painter; - SPPainter *stroke_painter; - // the 2 cached polygons, for rasterizations uses - Shape *fill_shp; - Shape *stroke_shp; - // the stroke width of stroke_shp, to detect when it changes (on normal/outline switching) and rebuild - float cached_width; + + cairo_path_t *path; + // delayed_shp=true means the *_shp polygons are not computed yet // they'll be computed on demand in *_render(), *_pick() or *_clip() // the goal is to not uncross polygons that are outside the viewing region bool delayed_shp; // approximate bounding box, for the case when the polygons have been delayed NRRectL approx_bbox; - // cache for transformations: cached_fill and cached_stroke are - // polygons computed for the cached_fctm and cache_sctm respectively - // when the transformation changes interactively (tracked by the - // SP_OBJECT_USER_MODIFIED_FLAG_B), we check if it's an isometry wrt - // the cached ctm. if it's an isometry, just apply it to the cached - // polygon to get the *_shp polygon. Otherwise, recompute so this - // works fine for translation and rotation, but not scaling and - // skewing - Geom::Affine cached_fctm; - Geom::Affine cached_sctm; - NRRectL cached_farea; - NRRectL cached_sarea; - bool cached_fpartialy; - bool cached_spartialy; - - Shape *cached_fill; - Shape *cached_stroke; + /* Markers */ NRArenaItem *markers; @@ -157,54 +54,7 @@ struct NRArenaShape : public NRArenaItem { return obj; } - void setFill(SPPaintServer *server); - void setFill(SPColor const &color); - void setFillOpacity(double opacity); - void setFillRule(FillRule rule); - - void setStroke(SPPaintServer *server); - void setStroke(SPColor const &color); - void setStrokeOpacity(double opacity); - void setStrokeWidth(double width); - void setLineCap(CapType cap); - void setLineJoin(JoinType join); - void setMitreLimit(double limit); - void setPaintBox(Geom::Rect const &pbox); - - void _invalidateCachedFill() { - if (cached_fill) { - delete cached_fill; - cached_fill = NULL; - } - } - void _invalidateCachedStroke() { - if (cached_stroke) { - delete cached_stroke; - cached_stroke = NULL; - } - } - - struct Style { - Style() : opacity(0.0) {} - Paint paint; - double opacity; - }; - struct FillStyle : public Style { - FillStyle() : rule(EVEN_ODD) {} - FillRule rule; - } _fill; - struct StrokeStyle : public Style { - StrokeStyle() - : cap(ROUND_CAP), join(ROUND_JOIN), - width(0.0), mitre_limit(0.0) - {} - - CapType cap; - JoinType join; - double width; - double mitre_limit; - } _stroke; }; struct NRArenaShapeClass { diff --git a/src/display/nr-arena.cpp b/src/display/nr-arena.cpp index 147269727..43edb6918 100644 --- a/src/display/nr-arena.cpp +++ b/src/display/nr-arena.cpp @@ -16,8 +16,6 @@ #include "nr-arena.h" #include "nr-filter-gaussian.h" #include "nr-filter-types.h" -#include <libnr/nr-blit.h> -#include "sp-paint-server.h" #include "preferences.h" #include "color.h" @@ -135,41 +133,6 @@ nr_arena_request_render_rect (NRArena *arena, NRRectL *area) } } -void -nr_arena_render_paintserver_fill (NRPixBlock *pb, NRRectL *area, SPPainter *painter, float opacity, NRPixBlock *mask) -{ - NRPixBlock cb, cb_opa; - nr_pixblock_setup_fast (&cb, NR_PIXBLOCK_MODE_R8G8B8A8N, area->x0, area->y0, area->x1, area->y1, TRUE); - nr_pixblock_setup_fast (&cb_opa, NR_PIXBLOCK_MODE_R8G8B8A8N, area->x0, area->y0, area->x1, area->y1, TRUE); - - // if memory allocation failed, abort - if ((cb.size != NR_PIXBLOCK_SIZE_TINY && cb.data.px == NULL) || (cb_opa.size != NR_PIXBLOCK_SIZE_TINY && cb_opa.data.px == NULL)) { - return; - } - - cb.visible_area = pb->visible_area; - cb_opa.visible_area = pb->visible_area; - - /* Need separate gradient buffer (lauris)*/ - // do the filling - painter->fill (painter, &cb); - cb.empty = FALSE; - - // do the fill-opacity and mask composite - if (opacity < 1.0) { - nr_blit_pixblock_pixblock_alpha (&cb_opa, &cb, (int) floor (255 * opacity)); - cb_opa.empty = FALSE; - nr_blit_pixblock_pixblock_mask (pb, &cb_opa, mask); - } else { - nr_blit_pixblock_pixblock_mask (pb, &cb, mask); - } - - pb->empty = FALSE; - - nr_pixblock_release (&cb); - nr_pixblock_release (&cb_opa); -} - /** set arena to offscreen mode rendering will be exact diff --git a/src/display/nr-arena.h b/src/display/nr-arena.h index 402bc198f..1c8216434 100644 --- a/src/display/nr-arena.h +++ b/src/display/nr-arena.h @@ -64,8 +64,6 @@ void nr_arena_request_update (NRArena *arena, NRArenaItem *item); void nr_arena_request_render_rect (NRArena *arena, NRRectL *area); void nr_arena_set_renderoffscreen (NRArena *arena); -void nr_arena_render_paintserver_fill (NRPixBlock *pb, NRRectL *area, SPPainter *painter, float opacity, NRPixBlock *mask); - void nr_arena_separate_color_plates(guint32* rgba); #endif diff --git a/src/display/nr-filter-blend.cpp b/src/display/nr-filter-blend.cpp index a0f074dc9..3cec479fa 100644 --- a/src/display/nr-filter-blend.cpp +++ b/src/display/nr-filter-blend.cpp @@ -15,15 +15,17 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "display/cairo-templates.h" +#include "display/cairo-utils.h" #include "display/nr-filter-blend.h" -#include "display/nr-filter-pixops.h" #include "display/nr-filter-primitive.h" #include "display/nr-filter-slot.h" #include "display/nr-filter-types.h" -#include "display/nr-filter-units.h" -#include "libnr/nr-pixblock.h" -#include "libnr/nr-blit.h" -#include "libnr/nr-pixops.h" +#include "preferences.h" namespace Inkscape { namespace Filters { @@ -42,77 +44,6 @@ namespace Filters { * cb = Color (RGB) at a given pixel for image B - premultiplied */ -/* - * These blending equations given in SVG standard are for color values - * in the range 0..1. As these values are stored as unsigned char values, - * they need some reworking. An unsigned char value can be thought as - * 0.8 fixed point representation of color value. This is how I've - * ended up with these equations here. - */ - -// Set alpha / opacity. This line is same for all the blending modes, -// so let's save some copy-pasting. -#define SET_ALPHA r[3] = NR_NORMALIZE_21((255 * 255) - (255 - a[3]) * (255 - b[3])) - -// cr = (1 - qa) * cb + ca -inline void -blend_normal(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - r[0] = NR_COMPOSEPPP_1111(a[0],a[3],b[0]); - r[1] = NR_COMPOSEPPP_1111(a[1],a[3],b[1]); - r[2] = NR_COMPOSEPPP_1111(a[2],a[3],b[2]); - SET_ALPHA; -} - -// cr = (1-qa)*cb + (1-qb)*ca + ca*cb -inline void -blend_multiply(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - r[0] = NR_NORMALIZE_21((255 - a[3]) * b[0] + (255 - b[3]) * a[0] - + a[0] * b[0]); - r[1] = NR_NORMALIZE_21((255 - a[3]) * b[1] + (255 - b[3]) * a[1] - + a[1] * b[1]); - r[2] = NR_NORMALIZE_21((255 - a[3]) * b[2] + (255 - b[3]) * a[2] - + a[2] * b[2]); - SET_ALPHA; -} - -// cr = cb + ca - ca * cb -inline void -blend_screen(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - r[0] = NR_NORMALIZE_21((b[0] + a[0]) * 255 - a[0] * b[0]); - r[1] = NR_NORMALIZE_21((b[1] + a[1]) * 255 - a[1] * b[1]); - r[2] = NR_NORMALIZE_21((b[2] + a[2]) * 255 - a[2] * b[2]); - SET_ALPHA; -} - -// cr = Min ((1 - qa) * cb + ca, (1 - qb) * ca + cb) -inline void -blend_darken(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - r[0] = NR_NORMALIZE_21(std::min(NR_COMPOSEPPP_1112(a[0],a[3],b[0]), - NR_COMPOSEPPP_1112(b[0],b[3],a[0]))); - r[1] = NR_NORMALIZE_21(std::min(NR_COMPOSEPPP_1112(a[1],a[3],b[1]), - NR_COMPOSEPPP_1112(b[1],b[3],a[1]))); - r[2] = NR_NORMALIZE_21(std::min(NR_COMPOSEPPP_1112(a[2],a[3],b[2]), - NR_COMPOSEPPP_1112(b[2],b[3],a[2]))); - SET_ALPHA; -} - -// cr = Max ((1 - qa) * cb + ca, (1 - qb) * ca + cb) -inline void -blend_lighten(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - r[0] = NR_NORMALIZE_21(std::max(NR_COMPOSEPPP_1112(a[0],a[3],b[0]), - NR_COMPOSEPPP_1112(b[0],b[3],a[0]))); - r[1] = NR_NORMALIZE_21(std::max(NR_COMPOSEPPP_1112(a[1],a[3],b[1]), - NR_COMPOSEPPP_1112(b[1],b[3],a[1]))); - r[2] = NR_NORMALIZE_21(std::max(NR_COMPOSEPPP_1112(a[2],a[3],b[2]), - NR_COMPOSEPPP_1112(b[2],b[3],a[2]))); - SET_ALPHA; -} - FilterBlend::FilterBlend() : _blend_mode(BLEND_NORMAL), _input2(NR_FILTER_SLOT_NOT_SET) @@ -125,81 +56,144 @@ FilterPrimitive * FilterBlend::create() { FilterBlend::~FilterBlend() {} -int FilterBlend::render(FilterSlot &slot, FilterUnits const & /*units*/) { - NRPixBlock *in1 = slot.get(_input); - NRPixBlock *in2 = slot.get(_input2); - NRPixBlock *original_in1 = in1; - NRPixBlock *original_in2 = in2; - NRPixBlock *out; - - // Bail out if either one of source images is missing - if (!in1 || !in2) { - g_warning("Missing source image for feBlend (in=%d in2=%d)", _input, _input2); - return 1; - } +// 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; - out = new NRPixBlock; - NRRectL out_area; - nr_rect_l_union(&out_area, &in1->area, &in2->area); - nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8P, - out_area.x0, out_area.y0, out_area.x1, out_area.y1, - true); - - // Blending modes are defined for premultiplied RGBA values, - // thus convert them to that format before blending - if (in1->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) { - in1 = new NRPixBlock; - nr_pixblock_setup_fast(in1, NR_PIXBLOCK_MODE_R8G8B8A8P, - original_in1->area.x0, original_in1->area.y0, - original_in1->area.x1, original_in1->area.y1, - false); - nr_blit_pixblock_pixblock(in1, original_in1); + ASSEMBLE_ARGB32(pxout, ao, ro, go, bo) + return pxout; } - if (in2->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) { - in2 = new NRPixBlock; - nr_pixblock_setup_fast(in2, NR_PIXBLOCK_MODE_R8G8B8A8P, - original_in2->area.x0, original_in2->area.y0, - original_in2->area.x1, original_in2->area.y1, - false); - nr_blit_pixblock_pixblock(in2, original_in2); +}; + +// 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; - /* pixops_mix is defined in display/nr-filter-pixops.h - * It mixes the two input images with the function given as template - * and places the result in output image. - */ - switch (_blend_mode) { - case BLEND_MULTIPLY: - pixops_mix<blend_multiply>(*out, *in1, *in2); - break; - case BLEND_SCREEN: - pixops_mix<blend_screen>(*out, *in1, *in2); - break; - case BLEND_DARKEN: - pixops_mix<blend_darken>(*out, *in1, *in2); - break; - case BLEND_LIGHTEN: - pixops_mix<blend_lighten>(*out, *in1, *in2); - break; - case BLEND_NORMAL: - default: - pixops_mix<blend_normal>(*out, *in1, *in2); - break; + ASSEMBLE_ARGB32(pxout, ao, ro, go, bo) + return pxout; } +}; - if (in1 != original_in1) { - nr_pixblock_release(in1); - delete in1; +// 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; } - if (in2 != original_in2) { - nr_pixblock_release(in2); - delete in2; +}; + +/* +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); + cairo_surface_t *input2 = slot.getcairo(_input2); + + cairo_content_t ct1 = cairo_surface_get_content(input1); + cairo_content_t ct2 = cairo_surface_get_content(input2); + + // input2 is the "background" image + // out should be ARGB32 if any of the inputs is ARGB32 + cairo_surface_t *out = ink_cairo_surface_create_output(input1, 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; + } } - out->empty = FALSE; slot.set(_output, out); + cairo_surface_destroy(out); +} - return 0; +bool FilterBlend::can_handle_affine(Geom::Affine const &) +{ + // blend is a per-pixel primitive and is immutable under transformations + return true; } void FilterBlend::set_input(int slot) { diff --git a/src/display/nr-filter-blend.h b/src/display/nr-filter-blend.h index 254653566..64b3c9284 100644 --- a/src/display/nr-filter-blend.h +++ b/src/display/nr-filter-blend.h @@ -18,8 +18,6 @@ */ #include "display/nr-filter-primitive.h" -#include "display/nr-filter-slot.h" -#include "display/nr-filter-units.h" namespace Inkscape { namespace Filters { @@ -39,7 +37,8 @@ public: static FilterPrimitive *create(); virtual ~FilterBlend(); - virtual int render(FilterSlot &slot, FilterUnits const &units); + virtual void render_cairo(FilterSlot &slot); + virtual bool can_handle_affine(Geom::Affine const &); virtual void set_input(int slot); virtual void set_input(int input, int slot); diff --git a/src/display/nr-filter-colormatrix.cpp b/src/display/nr-filter-colormatrix.cpp index 54d5dfd69..7eb2fa2e9 100644 --- a/src/display/nr-filter-colormatrix.cpp +++ b/src/display/nr-filter-colormatrix.cpp @@ -10,11 +10,13 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "display/nr-filter-colormatrix.h" -#include "display/nr-filter-units.h" -#include "display/nr-filter-utils.h" -#include "libnr/nr-blit.h" #include <math.h> +#include <algorithm> +#include "display/cairo-templates.h" +#include "display/cairo-utils.h" +#include "display/nr-filter-colormatrix.h" +#include "display/nr-filter-slot.h" +#include <2geom/math-utils.h> namespace Inkscape { namespace Filters { @@ -30,169 +32,160 @@ FilterPrimitive * FilterColorMatrix::create() { FilterColorMatrix::~FilterColorMatrix() {} -int FilterColorMatrix::render(FilterSlot &slot, FilterUnits const &/*units*/) { - NRPixBlock *in = slot.get(_input); - if (!in) { - g_warning("Missing source image for feColorMatrix (in=%d)", _input); - return 1; +struct ColorMatrixMatrix { + ColorMatrixMatrix(std::vector<double> const &values) { + unsigned limit = std::min(static_cast<size_t>(20), values.size()); + for (unsigned i = 0; i < limit; ++i) { + if (i % 5 == 4) { + _v[i] = round(values[i]*255*255); + } else { + _v[i] = round(values[i]*255); + } + } + for (unsigned i = limit; i < 20; ++i) { + _v[i] = 0; + } } - NRPixBlock *out = new NRPixBlock; - if ((type==COLORMATRIX_SATURATE || type==COLORMATRIX_HUEROTATE) && in->mode != NR_PIXBLOCK_MODE_R8G8B8A8N) { - // saturate and hueRotate do not touch the alpha channel and are linear (per-pixel) operations, so no premultiplied -> non-premultiplied operation is necessary - nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8P, - in->area.x0, in->area.y0, in->area.x1, in->area.y1, - true); - } else { - nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8N, - in->area.x0, in->area.y0, in->area.x1, in->area.y1, - true); + guint32 operator()(guint32 in) { + EXTRACT_ARGB32(in, a, r, g, b) + // we need to un-premultiply alpha values for this type of matrix + // TODO: unpremul can be ignored if there is an identity mapping on the alpha channel + if (a != 0) { + r = unpremul_alpha(r, a); + g = unpremul_alpha(g, a); + b = unpremul_alpha(b, a); + } + + gint32 ro = r*_v[0] + g*_v[1] + b*_v[2] + a*_v[3] + _v[4]; + gint32 go = r*_v[5] + g*_v[6] + b*_v[7] + a*_v[8] + _v[9]; + gint32 bo = r*_v[10] + g*_v[11] + b*_v[12] + a*_v[13] + _v[14]; + gint32 ao = r*_v[15] + g*_v[16] + b*_v[17] + a*_v[18] + _v[19]; + ro = (pxclamp(ro, 0, 255*255) + 127) / 255; + go = (pxclamp(go, 0, 255*255) + 127) / 255; + bo = (pxclamp(bo, 0, 255*255) + 127) / 255; + ao = (pxclamp(ao, 0, 255*255) + 127) / 255; + + ro = premul_alpha(ro, ao); + go = premul_alpha(go, ao); + bo = premul_alpha(bo, ao); + + ASSEMBLE_ARGB32(pxout, ao, ro, go, bo) + return pxout; + } +private: + gint32 _v[20]; +}; + +struct ColorMatrixSaturate { + ColorMatrixSaturate(double v_in) { + // clamp parameter instead of clamping color values + double v = CLAMP(v_in, 0.0, 1.0); + _v[0] = 0.213+0.787*v; _v[1] = 0.715-0.715*v; _v[2] = 0.072-0.072*v; + _v[3] = 0.213-0.213*v; _v[4] = 0.715+0.285*v; _v[5] = 0.072-0.072*v; + _v[6] = 0.213-0.213*v; _v[7] = 0.715-0.715*v; _v[8] = 0.072+0.928*v; } - // this primitive is defined for non-premultiplied RGBA values, - // thus convert them to that format - // However, since not all operations care, the input is only transformed if necessary. - bool free_in_on_exit = false; - if (in->mode != out->mode) { - NRPixBlock *original_in = in; - in = new NRPixBlock; - nr_pixblock_setup_fast(in, out->mode, - original_in->area.x0, original_in->area.y0, - original_in->area.x1, original_in->area.y1, - true); - nr_blit_pixblock_pixblock(in, original_in); - free_in_on_exit = true; + guint32 operator()(guint32 in) { + EXTRACT_ARGB32(in, a, r, g, b) + + // Note: this cannot be done in fixed point, because the loss of precision + // causes overflow for some values of v + guint32 ro = r*_v[0] + g*_v[1] + b*_v[2] + 0.5; + guint32 go = r*_v[3] + g*_v[4] + b*_v[5] + 0.5; + guint32 bo = r*_v[6] + g*_v[7] + b*_v[8] + 0.5; + + ASSEMBLE_ARGB32(pxout, a, ro, go, bo) + return pxout; + } +private: + double _v[9]; +}; + +struct ColorMatrixHueRotate { + ColorMatrixHueRotate(double v) { + double sinhue, coshue; + Geom::sincos(v * M_PI/180.0, sinhue, coshue); + + _v[0] = round((0.213 +0.787*coshue -0.213*sinhue)*255); + _v[1] = round((0.715 -0.715*coshue -0.715*sinhue)*255); + _v[2] = round((0.072 -0.072*coshue +0.928*sinhue)*255); + + _v[3] = round((0.213 -0.213*coshue +0.143*sinhue)*255); + _v[4] = round((0.715 +0.285*coshue +0.140*sinhue)*255); + _v[5] = round((0.072 -0.072*coshue -0.283*sinhue)*255); + + _v[6] = round((0.213 -0.213*coshue -0.787*sinhue)*255); + _v[7] = round((0.715 -0.715*coshue +0.715*sinhue)*255); + _v[8] = round((0.072 +0.928*coshue +0.072*sinhue)*255); + } + guint32 operator()(guint32 in) { + EXTRACT_ARGB32(in, a, r, g, b) + gint32 maxpx = a*255; + gint32 ro = r*_v[0] + g*_v[1] + b*_v[2]; + gint32 go = r*_v[3] + g*_v[4] + b*_v[5]; + gint32 bo = r*_v[6] + g*_v[7] + b*_v[8]; + ro = (pxclamp(ro, 0, maxpx) + 127) / 255; + go = (pxclamp(go, 0, maxpx) + 127) / 255; + bo = (pxclamp(bo, 0, maxpx) + 127) / 255; + + ASSEMBLE_ARGB32(pxout, a, ro, go, bo) + return pxout; + } +private: + gint32 _v[9]; +}; + +struct ColorMatrixLuminanceToAlpha { + guint32 operator()(guint32 in) { + // original computation in double: r*0.2125 + g*0.7154 + b*0.0721 + EXTRACT_ARGB32(in, a, r, g, b) + // unpremultiply color values + if (a != 0) { + r = unpremul_alpha(r, a); + g = unpremul_alpha(g, a); + b = unpremul_alpha(b, a); + } + guint32 ao = r*54 + g*182 + b*18; + return ((ao + 127) / 255) << 24; } +}; - unsigned char *in_data = NR_PIXBLOCK_PX(in); - unsigned char *out_data = NR_PIXBLOCK_PX(out); - unsigned char r,g,b,a; - int x,y,x0,y0,x1,y1,i; - x0=in->area.x0; - y0=in->area.y0; - x1=in->area.x1; - y1=in->area.y1; - - switch(type){ - case COLORMATRIX_MATRIX: - { - if (values.size()!=20) { - g_warning("ColorMatrix: values parameter error. Wrong size: %i.", static_cast<int>(values.size())); - return -1; - } - double a04 = 255*values[4]; - double a14 = 255*values[9]; - double a24 = 255*values[14]; - double a34 = 255*values[19]; - for (x=x0;x<x1;x++){ - for (y=y0;y<y1;y++){ - i = ((x-x0) + (x1-x0)*(y-y0))*4; - r = in_data[i]; - g = in_data[i+1]; - b = in_data[i+2]; - a = in_data[i+3]; - out_data[i] = CLAMP_D_TO_U8( r*values[0] + g*values[1] + b*values[2] + a*values[3] + a04 ); // CLAMP includes rounding! - out_data[i+1] = CLAMP_D_TO_U8( r*values[5] + g*values[6] + b*values[7] + a*values[8] + a14 ); - out_data[i+2] = CLAMP_D_TO_U8( r*values[10] + g*values[11] + b*values[12] + a*values[13] + a24 ); - out_data[i+3] = CLAMP_D_TO_U8( r*values[15] + g*values[16] + b*values[17] + a*values[18] + a34 ); - } - } - } - break; - case COLORMATRIX_SATURATE: - { - double v = std::max(0.0,std::min(1.0,value)); // The standard says it should be between 0 and 1, and clamping it here makes it unnecessary to clamp the color values. - double a00 = 0.213+0.787*v, a01 = 0.715-0.715*v, a02 = 0.072-0.072*v; - double a10 = 0.213-0.213*v, a11 = 0.715+0.285*v, a12 = 0.072-0.072*v; - double a20 = 0.213-0.213*v, a21 = 0.715-0.715*v, a22 = 0.072+0.928*v; - for (x=x0;x<x1;x++){ - for (y=y0;y<y1;y++){ - i = ((x-x0) + (x1-x0)*(y-y0))*4; - r = in_data[i]; - g = in_data[i+1]; - b = in_data[i+2]; - a = in_data[i+3]; - out_data[i] = static_cast<unsigned char>( r*a00 + g*a01 + b*a02 + .5 ); - out_data[i+1] = static_cast<unsigned char>( r*a10 + g*a11 + b*a12 + .5 ); - out_data[i+2] = static_cast<unsigned char>( r*a20 + g*a21 + b*a22 + .5 ); - out_data[i+3] = a; - } - } - } - break; - case COLORMATRIX_HUEROTATE: - { - double coshue = cos(value * M_PI/180.0); - double sinhue = sin(value * M_PI/180.0); - double a00 = 0.213 + coshue*( 0.787) + sinhue*(-0.213); - double a01 = 0.715 + coshue*(-0.715) + sinhue*(-0.715); - double a02 = 0.072 + coshue*(-0.072) + sinhue*( 0.928); - double a10 = 0.213 + coshue*(-0.213) + sinhue*( 0.143); - double a11 = 0.715 + coshue*( 0.285) + sinhue*( 0.140); - double a12 = 0.072 + coshue*(-0.072) + sinhue*(-0.283); - double a20 = 0.213 + coshue*(-0.213) + sinhue*(-0.787); - double a21 = 0.715 + coshue*(-0.715) + sinhue*( 0.715); - double a22 = 0.072 + coshue*( 0.928) + sinhue*( 0.072); - if (in->mode==NR_PIXBLOCK_MODE_R8G8B8A8P) { - // Although it does not change the alpha channel, it can give "out-of-bound" results, and in this case the bound is determined by the alpha channel - for (x=x0;x<x1;x++){ - for (y=y0;y<y1;y++){ - i = ((x-x0) + (x1-x0)*(y-y0))*4; - r = in_data[i]; - g = in_data[i+1]; - b = in_data[i+2]; - a = in_data[i+3]; - - out_data[i] = static_cast<unsigned char>(std::max(0.0,std::min((double)a, r*a00 + g*a01 + b*a02 + .5 ))); - out_data[i+1] = static_cast<unsigned char>(std::max(0.0,std::min((double)a, r*a10 + g*a11 + b*a12 + .5 ))); - out_data[i+2] = static_cast<unsigned char>(std::max(0.0,std::min((double)a, r*a20 + g*a21 + b*a22 + .5 ))); - out_data[i+3] = a; - } - } - } else { - for (x=x0;x<x1;x++){ - for (y=y0;y<y1;y++){ - i = ((x-x0) + (x1-x0)*(y-y0))*4; - r = in_data[i]; - g = in_data[i+1]; - b = in_data[i+2]; - a = in_data[i+3]; - - out_data[i] = CLAMP_D_TO_U8( r*a00 + g*a01 + b*a02); - out_data[i+1] = CLAMP_D_TO_U8( r*a10 + g*a11 + b*a12); - out_data[i+2] = CLAMP_D_TO_U8( r*a20 + g*a21 + b*a22); - out_data[i+3] = a; - } - } - } - } - break; - case COLORMATRIX_LUMINANCETOALPHA: - for (x=x0;x<x1;x++){ - for (y=y0;y<y1;y++){ - i = ((x-x0) + (x1-x0)*(y-y0))*4; - r = in_data[i]; - g = in_data[i+1]; - b = in_data[i+2]; - out_data[i] = 0; - out_data[i+1] = 0; - out_data[i+2] = 0; - out_data[i+3] = static_cast<unsigned char>( r*0.2125 + g*0.7154 + b*0.0721 + .5 ); - } - } - break; - case COLORMATRIX_ENDTYPE: - break; +void FilterColorMatrix::render_cairo(FilterSlot &slot) +{ + cairo_surface_t *input = slot.getcairo(_input); + cairo_surface_t *out = NULL; + if (type == COLORMATRIX_LUMINANCETOALPHA) { + out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_ALPHA); + } else { + out = ink_cairo_surface_create_identical(input); } - if (free_in_on_exit) { - nr_pixblock_release(in); - delete in; + switch (type) { + case COLORMATRIX_MATRIX: + ink_cairo_surface_filter(input, out, ColorMatrixMatrix(values)); + break; + case COLORMATRIX_SATURATE: + ink_cairo_surface_filter(input, out, ColorMatrixSaturate(value)); + break; + case COLORMATRIX_HUEROTATE: + ink_cairo_surface_filter(input, out, ColorMatrixHueRotate(value)); + break; + case COLORMATRIX_LUMINANCETOALPHA: + ink_cairo_surface_filter(input, out, ColorMatrixLuminanceToAlpha()); + break; + case COLORMATRIX_ENDTYPE: + default: + break; } - out->empty = FALSE; slot.set(_output, out); - return 0; + cairo_surface_destroy(out); +} + +bool FilterColorMatrix::can_handle_affine(Geom::Affine const &) +{ + return true; } void FilterColorMatrix::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*trans*/) @@ -207,7 +200,7 @@ void FilterColorMatrix::set_value(gdouble v){ value = v; } -void FilterColorMatrix::set_values(std::vector<gdouble> &v){ +void FilterColorMatrix::set_values(std::vector<gdouble> const &v){ values = v; } diff --git a/src/display/nr-filter-colormatrix.h b/src/display/nr-filter-colormatrix.h index 7a2395f5d..df851e0aa 100644 --- a/src/display/nr-filter-colormatrix.h +++ b/src/display/nr-filter-colormatrix.h @@ -12,14 +12,15 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <vector> +#include <2geom/forward.h> #include "display/nr-filter-primitive.h" -#include "display/nr-filter-slot.h" -#include "display/nr-filter-units.h" -#include<vector> namespace Inkscape { namespace Filters { +class FilterSlot; + enum FilterColorMatrixType { COLORMATRIX_MATRIX, COLORMATRIX_SATURATE, @@ -34,11 +35,13 @@ public: static FilterPrimitive *create(); virtual ~FilterColorMatrix(); - virtual int render(FilterSlot &slot, FilterUnits const &units); + virtual void render_cairo(FilterSlot &slot); + virtual bool can_handle_affine(Geom::Affine const &); virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); + virtual void set_type(FilterColorMatrixType type); virtual void set_value(gdouble value); - virtual void set_values(std::vector<gdouble> &values); + virtual void set_values(std::vector<gdouble> const &values); private: std::vector<gdouble> values; gdouble value; diff --git a/src/display/nr-filter-component-transfer.cpp b/src/display/nr-filter-component-transfer.cpp index 3fe8cbf4a..80bc07df8 100644 --- a/src/display/nr-filter-component-transfer.cpp +++ b/src/display/nr-filter-component-transfer.cpp @@ -10,13 +10,11 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "display/nr-filter-component-transfer.h" -#include "display/nr-filter-units.h" -#include "display/nr-filter-utils.h" -#include "libnr/nr-pixblock.h" -#include "libnr/nr-blit.h" -#include "libnr/nr-pixops.h" #include <math.h> +#include "display/cairo-templates.h" +#include "display/cairo-utils.h" +#include "display/nr-filter-component-transfer.h" +#include "display/nr-filter-slot.h" namespace Inkscape { namespace Filters { @@ -32,170 +30,278 @@ FilterPrimitive * FilterComponentTransfer::create() { FilterComponentTransfer::~FilterComponentTransfer() {} -int FilterComponentTransfer::render(FilterSlot &slot, FilterUnits const &/*units*/) { - NRPixBlock *in = slot.get(_input); +struct ComponentTransfer { + ComponentTransfer(guint32 color) + : _shift(color * 8) + , _mask(0xff << _shift) + {} +protected: + guint32 _shift; + guint32 _mask; +}; + +template <bool alpha> +struct ComponentTransferTable; + +template <> +struct ComponentTransferTable<false> : public ComponentTransfer { + ComponentTransferTable(guint32 color, std::vector<double> const &values) + : ComponentTransfer(color) + , _v(values.size()) + { + for (unsigned i = 0; i< values.size(); ++i) { + _v[i] = round(CLAMP(values[i], 0.0, 1.0) * 255); + } + } + guint32 operator()(guint32 in) { + guint32 component = (in & _mask) >> _shift; + guint32 alpha = (in & 0xff000000) >> 24; + if (alpha == 0) return in; + + component = (255 * component + alpha/2) / alpha; + guint32 k = (_v.size() - 1) * component; + guint32 dx = k % 255; k /= 255; + component = _v[k]*255 + (_v[k+1] - _v[k])*dx; + component = (component + 127) / 255; + component = premul_alpha(component, alpha); + return (in & ~_mask) | (component << _shift); + } +private: + std::vector<guint32> _v; +}; + +template <> +struct ComponentTransferTable<true> { + ComponentTransferTable(std::vector<double> const &values) + : _v(values.size()) + { + for (unsigned i = 0; i< values.size(); ++i) { + _v[i] = round(CLAMP(values[i], 0.0, 1.0) * 255); + } + } + guint32 operator()(guint32 in) { + guint32 alpha = (in & 0xff000000) >> 24; + if (alpha == 0) return in; + + guint32 k = (_v.size() - 1) * alpha; + guint32 dx = k % 255; k /= 255; + alpha = _v[k]*255 + (_v[k+1] - _v[k])*dx; + alpha = (alpha + 127) / 255; + return (in & 0x00ffffff) | (alpha << 24); + } +private: + std::vector<guint32> _v; +}; + +template <bool alpha> +struct ComponentTransferDiscrete; + +template <> +struct ComponentTransferDiscrete<false> : public ComponentTransfer { + ComponentTransferDiscrete(guint32 color, std::vector<double> const &values) + : ComponentTransfer(color) + , _v(values.size()) + { + for (unsigned i = 0; i< values.size(); ++i) { + _v[i] = round(CLAMP(values[i], 0.0, 1.0) * 255); + } + } + guint32 operator()(guint32 in) { + guint32 component = (in & _mask) >> _shift; + guint32 alpha = (in & 0xff000000) >> 24; + if (alpha == 0) return in; + + component = (255 * component + alpha/2) / alpha; + guint32 k = (_v.size() - 1) * component / 255; + component = _v[k]; + component = premul_alpha(component, alpha); + return (in & ~_mask) | (component << _shift); + } +private: + std::vector<guint32> _v; +}; + +template <> +struct ComponentTransferDiscrete<true> { + ComponentTransferDiscrete(std::vector<double> const &values) + : _v(values.size()) + { + for (unsigned i = 0; i< values.size(); ++i) { + _v[i] = round(CLAMP(values[i], 0.0, 1.0) * 255); + } + } + guint32 operator()(guint32 in) { + guint32 alpha = (in & 0xff000000) >> 24; + if (alpha == 0) return in; + + guint32 k = (_v.size() - 1) * alpha / 255; + alpha = _v[k]; + return (in & 0x00ffffff) | (alpha << 24); + } +private: + std::vector<guint32> _v; +}; + +template <bool alpha> +struct ComponentTransferLinear; + +template <> +struct ComponentTransferLinear<false> : public ComponentTransfer { + ComponentTransferLinear(guint32 color, double intercept, double slope) + : ComponentTransfer(color) + , _intercept(round(intercept*255*255)) + , _slope(round(slope*255)) + {} + guint32 operator()(guint32 in) { + gint32 component = (in & _mask) >> _shift; + guint32 alpha = (in & 0xff000000) >> 24; + if (alpha == 0) return 0; - if (!in) { - g_warning("Missing source image for feComponentTransfer (in=%d)", _input); - return 1; + // TODO: this can probably be reduced to something simpler + component = (255 * component + alpha/2) / alpha; + component = pxclamp(_slope * component + _intercept, 0, 255*255); + component = (component + 127) / 255; + component = premul_alpha(component, alpha); + return (in & ~_mask) | (component << _shift); } +private: + gint32 _intercept; + gint32 _slope; +}; - int x0=in->area.x0; - int x1=in->area.x1; - int y0=in->area.y0; - int y1=in->area.y1; - - // this primitive is defined for RGBA values, - // thus convert them to that format before blending - bool free_in_on_exit = false; - if (in->mode != NR_PIXBLOCK_MODE_R8G8B8A8N && in->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) { - NRPixBlock *original_in = in; - in = new NRPixBlock; - nr_pixblock_setup_fast(in, NR_PIXBLOCK_MODE_R8G8B8A8N, - original_in->area.x0, original_in->area.y0, - original_in->area.x1, original_in->area.y1, - false); - nr_blit_pixblock_pixblock(in, original_in); - free_in_on_exit = true; +template <> +struct ComponentTransferLinear<true> { + ComponentTransferLinear(double intercept, double slope) + : _intercept(round(intercept*255*255)) + , _slope(round(slope*255)) + {} + guint32 operator()(guint32 in) { + gint32 alpha = (in & 0xff000000) >> 24; + alpha = pxclamp(_slope * alpha + _intercept, 0, 255*255); + alpha = (alpha + 127) / 255; + return (in & 0x00ffffff) | (alpha << 24); } - bool premultiplied = in->mode == NR_PIXBLOCK_MODE_R8G8B8A8P; - - NRPixBlock *out = new NRPixBlock; - nr_pixblock_setup_fast(out, in->mode, x0, y0, x1, y1, true); - - unsigned char *in_data = NR_PIXBLOCK_PX(in); - unsigned char *out_data = NR_PIXBLOCK_PX(out); - - (void)in_data; - (void)out_data; - - int size = 4 * (y1-y0) * (x1-x0); - int i; - - int color=4; - while(color-->0) { - int _vsize = tableValues[color].size(); - double _intercept = intercept[color]; - double _slope = slope[color]; - double _amplitude = amplitude[color]; - double _exponent = exponent[color]; - double _offset = offset[color]; - switch(type[color]){ - case COMPONENTTRANSFER_TYPE_IDENTITY: - for(i=color;i<size;i+=4){ - out_data[i]=in_data[i]; - } - break; - case COMPONENTTRANSFER_TYPE_TABLE: - if (_vsize<=1){ - if (_vsize==1) { - g_warning("A component transfer table has to have at least two values."); - } - for(i=color;i<size;i+=4){ - out_data[i]=in_data[i]; - } - } else { - if (!premultiplied || color==3) { - std::vector<gdouble> _tableValues(tableValues[color]); - // Scale by 255 and add .5 to avoid having to add it later for rounding purposes - // Note that this means that CLAMP_D_TO_U8 cannot be used here (as it includes rounding!) - for(i=0;i<_vsize;i++) { - _tableValues[i] = std::max(0.,std::min(255.,255*_tableValues[i])) + .5; - } - for(i=color;i<size;i+=4){ - int k = FAST_DIVIDE<255>((_vsize-1) * in_data[i]); - double dx = ((_vsize-1) * in_data[i])/255.0 - k; - out_data[i] = static_cast<unsigned char>(_tableValues[k] + dx * (_tableValues[k+1] - _tableValues[k])); - } - } else { - std::vector<gdouble> _tableValues(tableValues[color]); - for(i=0;i<_vsize;i++) { - _tableValues[i] = std::max(0.,std::min(1.,_tableValues[i])); - } - for(i=color;i<size;i+=4){ - if (in_data[i+3-color]==0) continue; - int k = ((_vsize-1) * in_data[i]) / in_data[i+3-color]; - double dx = ((_vsize-1) * in_data[i]) / (double)in_data[i+3-color] - k; - out_data[i] = CLAMP_D_TO_U8_ALPHA(out_data[i+3-color] * (_tableValues[k] + dx * (_tableValues[k+1] - _tableValues[k])), out_data[i+3-color]); // CLAMP includes rounding! - } - } - } - break; - case COMPONENTTRANSFER_TYPE_DISCRETE: - if (_vsize==0){ - for(i=color;i<size;i+=4){ - out_data[i] = in_data[i]; - } - } else { - if (!premultiplied || color==3) { - std::vector<unsigned char> _tableValues(_vsize); - // Convert to unsigned char - for(i=0;i<_vsize;i++) { - _tableValues[i] = CLAMP_D_TO_U8(255*tableValues[color][i]); - } - for(i=color;i<size;i+=4){ - int k = FAST_DIVIDE<255>((_vsize-1) * in_data[i]); - out_data[i] = _tableValues[k]; - } - } else { - std::vector<gdouble> _tableValues(tableValues[color]); - for(i=0;i<_vsize;i++) { - _tableValues[i] = std::max(0.,std::min(1.,_tableValues[i])); - } - for(i=color;i<size;i+=4){ - if (in_data[i+3-color]==0) continue; - int k = ((_vsize-1) * in_data[i]) / in_data[i+3-color]; - out_data[i] = CLAMP_D_TO_U8_ALPHA(out_data[i+3-color] * _tableValues[k], out_data[i+3-color]); - } - } - } - break; - case COMPONENTTRANSFER_TYPE_LINEAR: - if (!premultiplied || color==3) { - _intercept = 255*_intercept; - for(i=color;i<size;i+=4){ - out_data[i] = CLAMP_D_TO_U8(_slope * in_data[i] + _intercept); // CLAMP includes rounding! - } - } else { - for(i=color;i<size;i+=4){ - if (in_data[i+3-color]==0) continue; - double out = _slope * in_data[i] / in_data[i+3-color] + _intercept; - out_data[i] = CLAMP_D_TO_U8_ALPHA(out_data[i+3-color] * out, out_data[i+3-color]); - } - } - break; - case COMPONENTTRANSFER_TYPE_GAMMA: - if (!premultiplied || color==3) { - _amplitude *= pow(255.0, -_exponent+1); // The input should be divided by 255, then exponentiated and then multiplied by 255 again, instead the amplitude is modified accordingly. - _offset = 255*_offset; - for(i=color;i<size;i+=4){ - out_data[i] = CLAMP_D_TO_U8(_amplitude * pow((double)in_data[i], _exponent) + _offset); - } - } else { - for(i=color;i<size;i+=4){ - if (in_data[i+3-color]==0) continue; - double out = _amplitude * pow((double)in_data[i] / in_data[i+3-color], _exponent) + _offset; - out_data[i] = CLAMP_D_TO_U8_ALPHA(out_data[i+3-color] * out, out_data[i+3-color]); - } - } - break; - case COMPONENTTRANSFER_TYPE_ERROR: - //TODO: report an error here - g_warning("Component tranfer type \"error\"."); - break; - default: - g_warning("Invalid tranfer type %d.", type[color]); +private: + gint32 _intercept; + gint32 _slope; +}; + +template <bool alpha> +struct ComponentTransferGamma; + +template <> +struct ComponentTransferGamma<false> : public ComponentTransfer { + ComponentTransferGamma(guint32 color, double amplitude, double exponent, double offset) + : ComponentTransfer(color) + , _amplitude(amplitude) + , _exponent(exponent) + , _offset(offset) + {} + guint32 operator()(guint32 in) { + double component = (in & _mask) >> _shift; + guint32 alpha = (in & 0xff000000) >> 24; + if (alpha == 0) return 0; + + double alphaf = alpha; + component /= alphaf; + component = _amplitude * pow(component, _exponent) + _offset; + guint32 cpx = pxclamp(component * alphaf, 0, 255); + return (in & ~_mask) | (cpx << _shift); + } +private: + double _amplitude; + double _exponent; + double _offset; +}; + +template <> +struct ComponentTransferGamma<true> { + ComponentTransferGamma(double amplitude, double exponent, double offset) + : _amplitude(amplitude) + , _exponent(exponent) + , _offset(offset) + {} + guint32 operator()(guint32 in) { + double alpha = (in & 0xff000000) >> 24; + alpha /= 255.0; + alpha = _amplitude * pow(alpha, _exponent) + _offset; + guint32 cpx = pxclamp(alpha * 255.0, 0, 255); + return (in & 0x00ffffff) | (cpx << 24); + } +private: + double _amplitude; + double _exponent; + double _offset; +}; + +void FilterComponentTransfer::render_cairo(FilterSlot &slot) +{ + cairo_surface_t *input = slot.getcairo(_input); + cairo_surface_t *out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_COLOR_ALPHA); + //cairo_surface_t *outtemp = ink_cairo_surface_create_identical(out); + ink_cairo_surface_blit(input, out); + + // parameters: R = 0, G = 1, B = 2, A = 3 + // Cairo: R = 2, G = 1, B = 0, A = 3 + for (unsigned i = 0; i < 3; ++i) { + guint32 color = 2 - i; + switch (type[i]) { + case COMPONENTTRANSFER_TYPE_TABLE: + ink_cairo_surface_filter(out, out, + ComponentTransferTable<false>(color, tableValues[i])); + break; + case COMPONENTTRANSFER_TYPE_DISCRETE: + ink_cairo_surface_filter(out, out, + ComponentTransferDiscrete<false>(color, tableValues[i])); + break; + case COMPONENTTRANSFER_TYPE_LINEAR: + ink_cairo_surface_filter(out, out, + ComponentTransferLinear<false>(color, intercept[i], slope[i])); + break; + case COMPONENTTRANSFER_TYPE_GAMMA: + ink_cairo_surface_filter(out, out, + ComponentTransferGamma<false>(color, amplitude[i], exponent[i], offset[i])); + break; + case COMPONENTTRANSFER_TYPE_ERROR: + case COMPONENTTRANSFER_TYPE_IDENTITY: + default: + break; } + //ink_cairo_surface_blit(out, outtemp); } - if (free_in_on_exit) { - nr_pixblock_release(in); - delete in; + // fast paths for alpha channel + switch (type[3]) { + case COMPONENTTRANSFER_TYPE_TABLE: + ink_cairo_surface_filter(out, out, + ComponentTransferTable<true>(tableValues[3])); + break; + case COMPONENTTRANSFER_TYPE_DISCRETE: + ink_cairo_surface_filter(out, out, + ComponentTransferDiscrete<true>(tableValues[3])); + break; + case COMPONENTTRANSFER_TYPE_LINEAR: + ink_cairo_surface_filter(out, out, + ComponentTransferLinear<true>(intercept[3], slope[3])); + break; + case COMPONENTTRANSFER_TYPE_GAMMA: + ink_cairo_surface_filter(out, out, + ComponentTransferGamma<true>(amplitude[3], exponent[3], offset[3])); + break; + case COMPONENTTRANSFER_TYPE_ERROR: + case COMPONENTTRANSFER_TYPE_IDENTITY: + default: + break; } - out->empty = FALSE; slot.set(_output, out); - return 0; + cairo_surface_destroy(out); + //cairo_surface_destroy(outtemp); +} + +bool FilterComponentTransfer::can_handle_affine(Geom::Affine const &) +{ + return true; } void FilterComponentTransfer::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*trans*/) diff --git a/src/display/nr-filter-component-transfer.h b/src/display/nr-filter-component-transfer.h index 65b4d4079..89bc61403 100644 --- a/src/display/nr-filter-component-transfer.h +++ b/src/display/nr-filter-component-transfer.h @@ -12,14 +12,14 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "display/nr-filter-primitive.h" -#include "display/nr-filter-slot.h" -#include "display/nr-filter-units.h" #include <vector> +#include "display/nr-filter-primitive.h" namespace Inkscape { namespace Filters { +class FilterSlot; + enum FilterComponentTransferType { COMPONENTTRANSFER_TYPE_IDENTITY, COMPONENTTRANSFER_TYPE_TABLE, @@ -35,7 +35,8 @@ public: static FilterPrimitive *create(); virtual ~FilterComponentTransfer(); - virtual int render(FilterSlot &slot, FilterUnits const &units); + virtual void render_cairo(FilterSlot &slot); + virtual bool can_handle_affine(Geom::Affine const &); virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); FilterComponentTransferType type[4]; diff --git a/src/display/nr-filter-composite.cpp b/src/display/nr-filter-composite.cpp index 41175ee07..d4cf47af4 100644 --- a/src/display/nr-filter-composite.cpp +++ b/src/display/nr-filter-composite.cpp @@ -12,77 +12,11 @@ #include <cmath> #include "2geom/isnan.h" -#include "filters/composite.h" +#include "display/cairo-templates.h" +#include "display/cairo-utils.h" #include "display/nr-filter-composite.h" -#include "display/nr-filter-pixops.h" #include "display/nr-filter-slot.h" #include "display/nr-filter-units.h" -#include "display/nr-filter-utils.h" -#include "libnr/nr-blit.h" -#include "libnr/nr-pixblock.h" -#include "libnr/nr-pixops.h" - -inline void -composite_over(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - r[0] = NR_COMPOSEPPP_1111(a[0],a[3],b[0]); - r[1] = NR_COMPOSEPPP_1111(a[1],a[3],b[1]); - r[2] = NR_COMPOSEPPP_1111(a[2],a[3],b[2]); - r[3] = NR_COMPOSEPPP_1111(a[3],a[3],b[3]); -} - -inline void -composite_in(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - r[0] = NR_NORMALIZE_21(a[0] * b[3]); - r[1] = NR_NORMALIZE_21(a[1] * b[3]); - r[2] = NR_NORMALIZE_21(a[2] * b[3]); - r[3] = NR_NORMALIZE_21(a[3] * b[3]); -} - -inline void -composite_out(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - r[0] = NR_NORMALIZE_21(a[0] * (255 - b[3])); - r[1] = NR_NORMALIZE_21(a[1] * (255 - b[3])); - r[2] = NR_NORMALIZE_21(a[2] * (255 - b[3])); - r[3] = NR_NORMALIZE_21(a[3] * (255 - b[3])); -} - -inline void -composite_atop(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - r[0] = NR_NORMALIZE_21(a[0] * b[3] + b[0] * (255 - a[3])); - r[1] = NR_NORMALIZE_21(a[1] * b[3] + b[1] * (255 - a[3])); - r[2] = NR_NORMALIZE_21(a[2] * b[3] + b[2] * (255 - a[3])); - r[3] = b[3]; -} - -inline void -composite_xor(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - r[0] = NR_NORMALIZE_21(a[0] * (255 - b[3]) + b[0] * (255 - a[3])); - r[1] = NR_NORMALIZE_21(a[1] * (255 - b[3]) + b[1] * (255 - a[3])); - r[2] = NR_NORMALIZE_21(a[2] * (255 - b[3]) + b[2] * (255 - a[3])); - r[3] = NR_NORMALIZE_21(a[3] * (255 - b[3]) + b[3] * (255 - a[3])); -} - -// BUGBUG / TODO -// This makes arithmetic compositing non re-entrant and non thread safe. -static int arith_k1, arith_k2, arith_k3, arith_k4; -inline void -composite_arithmetic(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - using Inkscape::Filters::clamp3; - r[0] = NR_NORMALIZE_31(clamp3(arith_k1 * a[0] * b[0] - + arith_k2 * a[0] + arith_k3 * b[0] + arith_k4)); - r[1] = NR_NORMALIZE_31(clamp3(arith_k1 * a[1] * b[1] - + arith_k2 * a[1] + arith_k3 * b[1] + arith_k4)); - r[2] = NR_NORMALIZE_31(clamp3(arith_k1 * a[2] * b[2] - + arith_k2 * a[2] + arith_k3 * b[2] + arith_k4)); - r[3] = NR_NORMALIZE_31(clamp3(arith_k1 * a[3] * b[3] - + arith_k2 * a[3] + arith_k3 * b[3] + arith_k4)); -} namespace Inkscape { namespace Filters { @@ -99,85 +33,77 @@ FilterPrimitive * FilterComposite::create() { FilterComposite::~FilterComposite() {} -int FilterComposite::render(FilterSlot &slot, FilterUnits const &/*units*/) { - NRPixBlock *in1 = slot.get(_input); - NRPixBlock *in2 = slot.get(_input2); - NRPixBlock *original_in1 = in1; - NRPixBlock *original_in2 = in2; - NRPixBlock *out; - - // Bail out if either one of source images is missing - if (!in1 || !in2) { - g_warning("Missing source image for feComposite (in=%d in2=%d)", _input, _input2); - return 1; - } - - out = new NRPixBlock; - NRRectL out_area; - nr_rect_l_union(&out_area, &in1->area, &in2->area); - nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8P, - out_area.x0, out_area.y0, out_area.x1, out_area.y1, - true); - - // Blending modes are defined for premultiplied RGBA values, - // thus convert them to that format before blending - if (in1->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) { - in1 = nr_pixblock_new_fast(NR_PIXBLOCK_MODE_R8G8B8A8P, - original_in1->area.x0, original_in1->area.y0, - original_in1->area.x1, original_in1->area.y1, - false); - nr_blit_pixblock_pixblock(in1, original_in1); - } - if (in2->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) { - in2 = nr_pixblock_new_fast(NR_PIXBLOCK_MODE_R8G8B8A8P, - original_in2->area.x0, original_in2->area.y0, - original_in2->area.x1, original_in2->area.y1, - false); - nr_blit_pixblock_pixblock(in2, original_in2); +struct ComposeArithmetic { + ComposeArithmetic(double k1, double k2, double k3, double k4) + : _k1(round(k1 * 255)) + , _k2(round(k2 * 255*255)) + , _k3(round(k3 * 255*255)) + , _k4(round(k4 * 255*255*255)) + {} + guint32 operator()(guint32 in1, guint32 in2) { + EXTRACT_ARGB32(in1, aa, ra, ga, ba) + EXTRACT_ARGB32(in2, ab, rb, gb, bb) + + gint32 ao = _k1*aa*ab + _k2*aa + _k3*ab + _k4; + gint32 ro = _k1*ra*rb + _k2*ra + _k3*rb + _k4; + gint32 go = _k1*ga*gb + _k2*ga + _k3*gb + _k4; + gint32 bo = _k1*ba*bb + _k2*ba + _k3*bb + _k4; + + ao = (pxclamp(ao, 0, 255*255*255) + (255*255/2)) / (255*255); + ro = (pxclamp(ro, 0, 255*255*255) + (255*255/2)) / (255*255); + go = (pxclamp(go, 0, 255*255*255) + (255*255/2)) / (255*255); + bo = (pxclamp(bo, 0, 255*255*255) + (255*255/2)) / (255*255); + + ASSEMBLE_ARGB32(pxout, ao, ro, go, bo) + return pxout; } +private: + gint32 _k1, _k2, _k3, _k4; +}; - /* pixops_mix is defined in display/nr-filter-pixops.h - * It mixes the two input images with the function given as template - * and places the result in output image. - */ - switch (op) { +void FilterComposite::render_cairo(FilterSlot &slot) +{ + cairo_surface_t *input1 = slot.getcairo(_input); + cairo_surface_t *input2 = slot.getcairo(_input2); + + cairo_surface_t *out = ink_cairo_surface_create_output(input1, input2); + + if (op == COMPOSITE_ARITHMETIC) { + ink_cairo_surface_blend(input1, input2, out, ComposeArithmetic(k1, k2, k3, k4)); + } else { + ink_cairo_surface_blit(input2, out); + cairo_t *ct = cairo_create(out); + cairo_set_source_surface(ct, input1, 0, 0); + switch(op) { case COMPOSITE_IN: - pixops_mix<composite_in>(*out, *in1, *in2); + cairo_set_operator(ct, CAIRO_OPERATOR_IN); break; case COMPOSITE_OUT: - pixops_mix<composite_out>(*out, *in1, *in2); + cairo_set_operator(ct, CAIRO_OPERATOR_OUT); break; case COMPOSITE_ATOP: - pixops_mix<composite_atop>(*out, *in1, *in2); + cairo_set_operator(ct, CAIRO_OPERATOR_ATOP); break; case COMPOSITE_XOR: - pixops_mix<composite_xor>(*out, *in1, *in2); - break; - case COMPOSITE_ARITHMETIC: - arith_k1 = (int)round(k1 * 255); - arith_k2 = (int)round(k2 * 255 * 255); - arith_k3 = (int)round(k3 * 255 * 255); - arith_k4 = (int)round(k4 * 255 * 255 * 255); - pixops_mix<composite_arithmetic>(*out, *in1, *in2); + cairo_set_operator(ct, CAIRO_OPERATOR_XOR); break; - case COMPOSITE_DEFAULT: case COMPOSITE_OVER: + case COMPOSITE_DEFAULT: default: - pixops_mix<composite_over>(*out, *in1, *in2); + // OVER is the default operator break; + } + cairo_paint(ct); + cairo_destroy(ct); } - if (in1 != original_in1) { - nr_pixblock_free(in1); - } - if (in2 != original_in2) { - nr_pixblock_free(in2); - } - - out->empty = FALSE; slot.set(_output, out); + cairo_surface_destroy(out); +} - return 0; +bool FilterComposite::can_handle_affine(Geom::Affine const &) +{ + return true; } void FilterComposite::set_input(int input) { diff --git a/src/display/nr-filter-composite.h b/src/display/nr-filter-composite.h index 45114a92c..930898830 100644 --- a/src/display/nr-filter-composite.h +++ b/src/display/nr-filter-composite.h @@ -26,7 +26,8 @@ public: static FilterPrimitive *create(); virtual ~FilterComposite(); - virtual int render(FilterSlot &slot, FilterUnits const &units); + virtual void render_cairo(FilterSlot &); + virtual bool can_handle_affine(Geom::Affine const &); virtual void set_input(int input); virtual void set_input(int input, int slot); diff --git a/src/display/nr-filter-convolve-matrix.cpp b/src/display/nr-filter-convolve-matrix.cpp index f5cc7175a..06e28b074 100644 --- a/src/display/nr-filter-convolve-matrix.cpp +++ b/src/display/nr-filter-convolve-matrix.cpp @@ -10,10 +10,13 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <vector> +#include "display/cairo-templates.h" +#include "display/cairo-utils.h" #include "display/nr-filter-convolve-matrix.h" +#include "display/nr-filter-slot.h" #include "display/nr-filter-units.h" #include "display/nr-filter-utils.h" -#include <vector> namespace Inkscape { namespace Filters { @@ -28,186 +31,139 @@ FilterPrimitive * FilterConvolveMatrix::create() { FilterConvolveMatrix::~FilterConvolveMatrix() {} -template<bool PREMULTIPLIED, bool PRESERVE_ALPHA, bool X_LOWER, bool X_UPPER, bool Y_LOWER, bool Y_UPPER> -static inline void convolve2D_XY(unsigned int const x, unsigned int const y, unsigned char *const out_data, unsigned char const *const in_data, unsigned int const width, unsigned int const height, double const *const kernel, unsigned int const orderX, unsigned int const orderY, unsigned int const targetX, unsigned int const targetY, double const bias) { - double result_R = 0; - double result_G = 0; - double result_B = 0; - double result_A = 0; - - unsigned int iBegin = Y_LOWER ? targetY-y : 0; // Note that to prevent signed/unsigned problems this requires that y<=targetY (which is true) - unsigned int iEnd = Y_UPPER ? height+targetY-y : orderY; // And this requires that y<=height+targetY (which is trivially true), in addition it should be true that height+targetY-y<=orderY (or equivalently y>=height+targetY-orderY, which is true) - unsigned int jBegin = X_LOWER ? targetX-x : 0; - unsigned int jEnd = X_UPPER ? width+targetX-x : orderX; - - for (unsigned int i=iBegin; i<iEnd; i++){ - for (unsigned int j=jBegin; j<jEnd; j++){ - unsigned int index = 4*( x - targetX + j + width*(y - targetY + i) ); - unsigned int kernel_index = orderX-j-1 + orderX*(orderY-i-1); - double k = PREMULTIPLIED ? kernel[kernel_index] : in_data[index+3] * kernel[kernel_index]; - result_R += in_data[index+0] * k; - result_G += in_data[index+1] * k; - result_B += in_data[index+2] * k; - result_A += in_data[index+3] * kernel[kernel_index]; +enum PreserveAlphaMode { + PRESERVE_ALPHA, + NO_PRESERVE_ALPHA +}; + +template <PreserveAlphaMode preserve_alpha> +struct ConvolveMatrix : public SurfaceSynth { + ConvolveMatrix(cairo_surface_t *s, int targetX, int targetY, int orderX, int orderY, + double divisor, double bias, std::vector<double> const &kernel) + : SurfaceSynth(s) + , _kernel(kernel.size()) + , _targetX(targetX) + , _targetY(targetY) + , _orderX(orderX) + , _orderY(orderY) + , _bias(bias) + { + for (unsigned i = 0; i < _kernel.size(); ++i) { + _kernel[i] = kernel[i] / divisor; } - } - - unsigned int const out_index = 4*( x + width*y ); - if (PRESERVE_ALPHA) { - out_data[out_index+3] = in_data[out_index+3]; - } else if (PREMULTIPLIED) { - out_data[out_index+3] = CLAMP_D_TO_U8(result_A + 255*bias); - } else { - out_data[out_index+3] = CLAMP_D_TO_U8(result_A + bias); - } - if (PREMULTIPLIED) { - out_data[out_index+0] = CLAMP_D_TO_U8_ALPHA(result_R + out_data[out_index+3]*bias, out_data[out_index+3]); // CLAMP includes rounding! - out_data[out_index+1] = CLAMP_D_TO_U8_ALPHA(result_G + out_data[out_index+3]*bias, out_data[out_index+3]); - out_data[out_index+2] = CLAMP_D_TO_U8_ALPHA(result_B + out_data[out_index+3]*bias, out_data[out_index+3]); - } else if (out_data[out_index+3]==0) { - out_data[out_index+0] = 0; // TODO: Is there a more sensible value that can be used here? - out_data[out_index+1] = 0; - out_data[out_index+2] = 0; - } else { - out_data[out_index+0] = CLAMP_D_TO_U8(result_R / out_data[out_index+3] + bias); // CLAMP includes rounding! - out_data[out_index+1] = CLAMP_D_TO_U8(result_G / out_data[out_index+3] + bias); - out_data[out_index+2] = CLAMP_D_TO_U8(result_B / out_data[out_index+3] + bias); - } -} - -template<bool PREMULTIPLIED, bool PRESERVE_ALPHA, bool Y_LOWER, bool Y_UPPER> -static inline void convolve2D_Y(unsigned int const y, unsigned char *const out_data, unsigned char const *const in_data, unsigned int const width, unsigned int const height, double const *const kernel, unsigned int const orderX, unsigned int const orderY, unsigned int const targetX, unsigned int const targetY, double const bias) { - // See convolve2D below for rationale. - - unsigned int const lowerEnd = std::min(targetX,width); - unsigned int const upperBegin = width - std::min<unsigned int>(width,orderX - 1u - targetX); - unsigned int const midXBegin = std::min(lowerEnd,upperBegin); - unsigned int const midXEnd = std::max(lowerEnd,upperBegin); - - for (unsigned int x=0; x<midXBegin; x++) { - convolve2D_XY<PREMULTIPLIED,PRESERVE_ALPHA,true,false,Y_LOWER,Y_UPPER>(x, y, out_data, in_data, width, height, kernel, orderX, orderY, targetX, targetY, bias); - } - if (lowerEnd==upperBegin) { - // Do nothing, empty mid section - } else if (lowerEnd<upperBegin) { - // In the middle no bounds have to be adjusted - for (unsigned int x=midXBegin; x<midXEnd; x++) { - convolve2D_XY<PREMULTIPLIED,PRESERVE_ALPHA,false,false,Y_LOWER,Y_UPPER>(x, y, out_data, in_data, width, height, kernel, orderX, orderY, targetX, targetY, bias); + // the matrix is given rotated 180 degrees + // which corresponds to reverse element order + std::reverse(_kernel.begin(), _kernel.end()); + } + + guint32 operator()(int x, int y) const { + int startx = std::max(0, x - _targetX); + int starty = std::max(0, y - _targetY); + int endx = std::min(_w, startx + _orderX); + int endy = std::min(_h, starty + _orderY); + int limitx = endx - startx; + int limity = endy - starty; + double suma = 0.0, sumr = 0.0, sumg = 0.0, sumb = 0.0; + + for (int i = 0; i < limity; ++i) { + for (int j = 0; j < limitx; ++j) { + guint32 px = pixelAt(startx + j, starty + i); + double coeff = _kernel[i * _orderX + j]; + EXTRACT_ARGB32(px, a,r,g,b) + + sumr += r * coeff; + sumg += g * coeff; + sumb += b * coeff; + if (preserve_alpha == NO_PRESERVE_ALPHA) { + suma += a * coeff; + } + } } - } else { - // In the middle both bounds have to be adjusted - for (unsigned int x=midXBegin; x<midXEnd; x++) { - convolve2D_XY<PREMULTIPLIED,PRESERVE_ALPHA,true,true,Y_LOWER,Y_UPPER>(x, y, out_data, in_data, width, height, kernel, orderX, orderY, targetX, targetY, bias); + if (preserve_alpha == PRESERVE_ALPHA) { + suma = alphaAt(x, y); + } else { + suma += _bias * 255; } + + guint32 ao = pxclamp(round(suma), 0, 255); + guint32 ro = pxclamp(round(sumr + ao * _bias), 0, ao); + guint32 go = pxclamp(round(sumg + ao * _bias), 0, ao); + guint32 bo = pxclamp(round(sumb + ao * _bias), 0, ao); + ASSEMBLE_ARGB32(pxout, ao,ro,go,bo); + return pxout; } - for (unsigned int x=midXEnd; x<width; x++) { - convolve2D_XY<PREMULTIPLIED,PRESERVE_ALPHA,false,true,Y_LOWER,Y_UPPER>(x, y, out_data, in_data, width, height, kernel, orderX, orderY, targetX, targetY, bias); - } -} -template<bool PREMULTIPLIED, bool PRESERVE_ALPHA> -static void convolve2D(unsigned char *const out_data, unsigned char const *const in_data, unsigned int const width, unsigned int const height, double const *const kernel, unsigned int const orderX, unsigned int const orderY, unsigned int const targetX, unsigned int const targetY, double const _bias) { - double const bias = PREMULTIPLIED ? _bias : 255*_bias; // If we're using non-premultiplied values the bias is always multiplied by 255. +private: + std::vector<double> _kernel; + int _targetX, _targetY, _orderX, _orderY; + double _bias; +}; - // For the middle section it should hold that (for all i such that 0<=i<orderY): - // 0 <= y - targetY + i < height - // targetY <= y && y < height + targetY - orderY + 1 - // In other words, for y<targetY i's lower bound needs to be adjusted and for y>=height+targetY-orderY+1 i's upper bound needs to be adjusted. +void FilterConvolveMatrix::render_cairo(FilterSlot &slot) +{ + static bool bias_warning = false; + static bool edge_warning = false; - unsigned int const lowerEnd = std::min(targetY,height); - unsigned int const upperBegin = height - std::min<unsigned int>(height,orderY - 1u - targetY); - unsigned int const midYBegin = std::min(lowerEnd,upperBegin); - unsigned int const midYEnd = std::max(lowerEnd,upperBegin); + cairo_surface_t *input = slot.getcairo(_input); - for (unsigned int y=0; y<midYBegin; y++) { - convolve2D_Y<PREMULTIPLIED,PRESERVE_ALPHA,true,false>(y, out_data, in_data, width, height, kernel, orderX, orderY, targetX, targetY, bias); - } - if (lowerEnd==upperBegin) { - // Do nothing, empty mid section - } else if (lowerEnd<upperBegin) { - // In the middle no bounds have to be adjusted - for (unsigned int y=midYBegin; y<midYEnd; y++) { - convolve2D_Y<PREMULTIPLIED,PRESERVE_ALPHA,false,false>(y, out_data, in_data, width, height, kernel, orderX, orderY, targetX, targetY, bias); - } - } else { - // In the middle both bounds have to be adjusted - for (unsigned int y=midYBegin; y<midYEnd; y++) { - convolve2D_Y<PREMULTIPLIED,PRESERVE_ALPHA,true,true>(y, out_data, in_data, width, height, kernel, orderX, orderY, targetX, targetY, bias); - } - } - for (unsigned int y=midYEnd; y<height; y++) { - convolve2D_Y<PREMULTIPLIED,PRESERVE_ALPHA,false,true>(y, out_data, in_data, width, height, kernel, orderX, orderY, targetX, targetY, bias); - } -} - -int FilterConvolveMatrix::render(FilterSlot &slot, FilterUnits const &/*units*/) { - NRPixBlock *in = slot.get(_input); - if (!in) { - g_warning("Missing source image for feConvolveMatrix (in=%d)", _input); - return 1; - } if (orderX<=0 || orderY<=0) { g_warning("Empty kernel!"); - return 1; + return; } if (targetX<0 || targetX>=orderX || targetY<0 || targetY>=orderY) { g_warning("Invalid target!"); - return 1; + return; } if (kernelMatrix.size()!=(unsigned int)(orderX*orderY)) { - g_warning("kernelMatrix does not have orderX*orderY elements!"); - return 1; - } - - if (bias!=0) { - g_warning("It is unknown whether Inkscape's implementation of bias in feConvolveMatrix is correct!"); - // The SVG specification implies that feConvolveMatrix is defined for premultiplied colors (which makes sense). - // It also says that bias should simply be added to the result for each color (without taking the alpha into account) - // However, it also says that one purpose of bias is "to have .5 gray value be the zero response of the filter". - // It seems sensible to indeed support the latter behaviour instead of the former, but this does appear to go against the standard. + //g_warning("kernelMatrix does not have orderX*orderY elements!"); + return; + } + + cairo_surface_t *out = ink_cairo_surface_create_identical(input); + + if (bias!=0 && !bias_warning) { + g_warning("It is unknown whether Inkscape's implementation of bias in feConvolveMatrix " + "is correct!"); + bias_warning = true; + // The SVG specification implies that feConvolveMatrix is defined for premultiplied + // colors (which makes sense). It also says that bias should simply be added to the result + // for each color (without taking the alpha into account). However, it also says that one + // purpose of bias is "to have .5 gray value be the zero response of the filter". + // It seems sensible to indeed support the latter behaviour instead of the former, + // but this does appear to go against the standard. // Note that Batik simply does not support bias!=0 } - if (edgeMode!=CONVOLVEMATRIX_EDGEMODE_NONE) { + if (edgeMode!=CONVOLVEMATRIX_EDGEMODE_NONE && !edge_warning) { g_warning("Inkscape only supports edgeMode=\"none\" (and a filter uses a different one)!"); - // Note that to properly support edgeMode the interaction with area_enlarge should be well understood (and probably something needs to change) - // area_enlarge should NOT let Inkscape enlarge the area beyond the filter area, it should only enlarge the rendered area if a part of the object is rendered to make it overlapping (enough) with adjacent parts. + edge_warning = true; } - NRPixBlock *out = new NRPixBlock; + //guint32 *in_data = reinterpret_cast<guint32*>(cairo_image_surface_get_data(input)); + //guint32 *out_data = reinterpret_cast<guint32*>(cairo_image_surface_get_data(out)); - nr_pixblock_setup_fast(out, in->mode, - in->area.x0, in->area.y0, in->area.x1, in->area.y1, - true); - - unsigned char *in_data = NR_PIXBLOCK_PX(in); - unsigned char *out_data = NR_PIXBLOCK_PX(out); - - unsigned int const width = in->area.x1 - in->area.x0; - unsigned int const height = in->area.y1 - in->area.y0; + //int width = cairo_image_surface_get_width(input); + //int height = cairo_image_surface_get_height(input); // Set up predivided kernel matrix - std::vector<double> kernel(kernelMatrix); + /*std::vector<double> kernel(kernelMatrix); for(size_t i=0; i<kernel.size(); i++) { kernel[i] /= divisor; // The code that creates this object makes sure that divisor != 0 - } + }*/ - if (in->mode==NR_PIXBLOCK_MODE_R8G8B8A8P) { - if (preserveAlpha) { - convolve2D<true,true>(out_data, in_data, width, height, &kernel.front(), orderX, orderY, targetX, targetY, bias); - } else { - convolve2D<true,false>(out_data, in_data, width, height, &kernel.front(), orderX, orderY, targetX, targetY, bias); - } + if (preserveAlpha) { + //convolve2D<true>(out_data, in_data, width, height, &kernel.front(), orderX, orderY, + // targetX, targetY, bias); + ink_cairo_surface_synthesize(out, ConvolveMatrix<PRESERVE_ALPHA>(input, + targetX, targetY, orderX, orderY, divisor, bias, kernelMatrix)); } else { - if (preserveAlpha) { - convolve2D<false,true>(out_data, in_data, width, height, &kernel.front(), orderX, orderY, targetX, targetY, bias); - } else { - convolve2D<false,false>(out_data, in_data, width, height, &kernel.front(), orderX, orderY, targetX, targetY, bias); - } + //convolve2D<false>(out_data, in_data, width, height, &kernel.front(), orderX, orderY, + // targetX, targetY, bias); + ink_cairo_surface_synthesize(out, ConvolveMatrix<NO_PRESERVE_ALPHA>(input, + targetX, targetY, orderX, orderY, divisor, bias, kernelMatrix)); } - out->empty = FALSE; slot.set(_output, out); - return 0; + cairo_surface_destroy(out); } void FilterConvolveMatrix::set_targetX(int coord) { @@ -256,10 +212,6 @@ void FilterConvolveMatrix::area_enlarge(NRRectL &area, Geom::Affine const &/*tra area.y1 += orderY - targetY - 1; } -FilterTraits FilterConvolveMatrix::get_input_traits() { - return TRAIT_PARALLER; -} - } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-convolve-matrix.h b/src/display/nr-filter-convolve-matrix.h index 50d97f1a0..d13738260 100644 --- a/src/display/nr-filter-convolve-matrix.h +++ b/src/display/nr-filter-convolve-matrix.h @@ -13,14 +13,14 @@ */ #include "display/nr-filter-primitive.h" -#include "display/nr-filter-slot.h" -#include "display/nr-filter-units.h" #include "libnr/nr-rect-l.h" #include <vector> namespace Inkscape { namespace Filters { +class FilterSlot; + enum FilterConvolveMatrixEdgeMode { CONVOLVEMATRIX_EDGEMODE_DUPLICATE, CONVOLVEMATRIX_EDGEMODE_WRAP, @@ -34,9 +34,8 @@ public: static FilterPrimitive *create(); virtual ~FilterConvolveMatrix(); - virtual int render(FilterSlot &slot, FilterUnits const &units); + virtual void render_cairo(FilterSlot &slot); virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); - virtual FilterTraits get_input_traits(); void set_targetY(int coord); void set_targetX(int coord); diff --git a/src/display/nr-filter-diffuselighting.cpp b/src/display/nr-filter-diffuselighting.cpp index 8e764f6d4..0a46a5c86 100644 --- a/src/display/nr-filter-diffuselighting.cpp +++ b/src/display/nr-filter-diffuselighting.cpp @@ -4,26 +4,25 @@ * Authors: * Niko Kiirala <niko@kiirala.com> * Jean-Rene Reinhard <jr@komite.net> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> * - * Copyright (C) 2007 authors + * Copyright (C) 2007-2010 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ #include <glib/gmessages.h> +#include "display/cairo-templates.h" +#include "display/cairo-utils.h" #include "display/nr-3dutils.h" #include "display/nr-arena-item.h" #include "display/nr-filter-diffuselighting.h" -#include "display/nr-filter-getalpha.h" #include "display/nr-filter-slot.h" #include "display/nr-filter-units.h" #include "display/nr-filter-utils.h" #include "display/nr-light.h" -#include "libnr/nr-blit.h" -#include "libnr/nr-pixblock.h" #include "libnr/nr-rect-l.h" -#include "color.h" namespace Inkscape { namespace Filters { @@ -43,146 +42,134 @@ FilterPrimitive * FilterDiffuseLighting::create() { FilterDiffuseLighting::~FilterDiffuseLighting() {} -int FilterDiffuseLighting::render(FilterSlot &slot, FilterUnits const &units) { - NRPixBlock *in = slot.get(_input); - if (!in) { - g_warning("Missing source image for feDiffuseLighting (in=%d)", _input); - return 1; +struct DiffuseLight : public SurfaceSynth { + DiffuseLight(cairo_surface_t *bumpmap, double scale, double kd) + : SurfaceSynth(bumpmap) + , _scale(scale) + , _kd(kd) + {} + +protected: + guint32 diffuseLighting(int x, int y, NR::Fvector const &light, NR::Fvector const &light_components) { + NR::Fvector normal = surfaceNormalAt(x, y, _scale); + double k = _kd * NR::scalar_product(normal, light); + + guint32 r = CLAMP_D_TO_U8(k * light_components[LIGHT_RED]); + guint32 g = CLAMP_D_TO_U8(k * light_components[LIGHT_GREEN]); + guint32 b = CLAMP_D_TO_U8(k * light_components[LIGHT_BLUE]); + + ASSEMBLE_ARGB32(pxout, 255,r,g,b) + return pxout; + } + double _scale, _kd; +}; + +struct DiffuseDistantLight : public DiffuseLight { + DiffuseDistantLight(cairo_surface_t *bumpmap, SPFeDistantLight *light, guint32 color, + double scale, double diffuse_constant) + : DiffuseLight(bumpmap, scale, diffuse_constant) + { + DistantLight dl(light, color); + dl.light_vector(_lightv); + dl.light_components(_light_components); } - NRPixBlock *out = new NRPixBlock; - - int w = in->area.x1 - in->area.x0; - int h = in->area.y1 - in->area.y0; - int x0 = in->area.x0; - int y0 = in->area.y0; - int i, j; - //As long as FilterRes and kernel unit is not supported we hardcode the - //default value - int dx = 1; //TODO setup - int dy = 1; //TODO setup - //surface scale - Geom::Affine trans = units.get_matrix_primitiveunits2pb(); - gdouble ss = surfaceScale * trans[0]; - gdouble kd = diffuseConstant; //diffuse lighting constant - - NR::Fvector L, N, LC; - gdouble inter; - - nr_pixblock_setup_fast(out, in->mode, - in->area.x0, in->area.y0, in->area.x1, in->area.y1, - true); - unsigned char *data_i = NR_PIXBLOCK_PX (in); - unsigned char *data_o = NR_PIXBLOCK_PX (out); - //No light, nothing to do + guint32 operator()(int x, int y) { + return diffuseLighting(x, y, _lightv, _light_components); + } +private: + NR::Fvector _lightv, _light_components; +}; + +struct DiffusePointLight : public DiffuseLight { + DiffusePointLight(cairo_surface_t *bumpmap, SPFePointLight *light, guint32 color, + Geom::Affine const &trans, double scale, double diffuse_constant, double x0, double y0) + : DiffuseLight(bumpmap, scale, diffuse_constant) + , _light(light, color, trans) + , _x0(x0) + , _y0(y0) + { + _light.light_components(_light_components); + } + + guint32 operator()(int x, int y) { + NR::Fvector light; + _light.light_vector(light, _x0 + x, _y0 + y, _scale * alphaAt(x, y)/255.0); + return diffuseLighting(x, y, light, _light_components); + } +private: + PointLight _light; + NR::Fvector _light_components; + double _x0, _y0; +}; + +struct DiffuseSpotLight : public DiffuseLight { + DiffuseSpotLight(cairo_surface_t *bumpmap, SPFeSpotLight *light, guint32 color, + Geom::Affine const &trans, double scale, double diffuse_constant, double x0, double y0) + : DiffuseLight(bumpmap, scale, diffuse_constant) + , _light(light, color, trans) + , _x0(x0) + , _y0(y0) + {} + + guint32 operator()(int x, int y) { + NR::Fvector light, light_components; + _light.light_vector(light, _x0 + x, _y0 + y, _scale * alphaAt(x, y)/255.0); + _light.light_components(light_components, light); + return diffuseLighting(x, y, light, light_components); + } +private: + SpotLight _light; + double _x0, _y0; +}; + +void FilterDiffuseLighting::render_cairo(FilterSlot &slot) +{ + cairo_surface_t *input = slot.getcairo(_input); + cairo_surface_t *out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_COLOR_ALPHA); + + Geom::Rect slot_area = slot.get_slot_area(); + Geom::Point p = slot_area.min(); + Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); + double x0 = p[Geom::X], y0 = p[Geom::Y]; + double scale = surfaceScale * trans.descrim(); + switch (light_type) { - case DISTANT_LIGHT: - //the light vector is constant - { - DistantLight *dl = new DistantLight(light.distant, lighting_color); - dl->light_vector(L); - dl->light_components(LC); - //finish the work - for (i = 0, j = 0; i < w*h; i++) { - NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy); - inter = kd * NR::scalar_product(N, L); - - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]); // CLAMP includes rounding! - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]); - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]); - data_o[j++] = 255; - } - out->empty = FALSE; - delete dl; - } - break; - case POINT_LIGHT: - { - PointLight *pl = new PointLight(light.point, lighting_color, trans); - pl->light_components(LC); - //TODO we need a reference to the filter to determine primitiveUnits - //if objectBoundingBox is used, use a different matrix for light_vector - // UPDATE: trans is now correct matrix from primitiveUnits to - // pixblock coordinates - //finish the work - for (i = 0, j = 0; i < w*h; i++) { - NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy); - pl->light_vector(L, - i % w + x0, - i / w + y0, - ss * (double) data_i[4*i+3]/ 255); - inter = kd * NR::scalar_product(N, L); - - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]); - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]); - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]); - data_o[j++] = 255; - } - out->empty = FALSE; - delete pl; - } - break; - case SPOT_LIGHT: - { - SpotLight *sl = new SpotLight(light.spot, lighting_color, trans); - //TODO we need a reference to the filter to determine primitiveUnits - //if objectBoundingBox is used, use a different matrix for light_vector - // UPDATE: trans is now correct matrix from primitiveUnits to - // pixblock coordinates - //finish the work - for (i = 0, j = 0; i < w*h; i++) { - NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy); - sl->light_vector(L, - i % w + x0, - i / w + y0, - ss * (double) data_i[4*i+3]/ 255); - sl->light_components(LC, L); - inter = kd * NR::scalar_product(N, L); - - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]); - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]); - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]); - data_o[j++] = 255; - } - out->empty = FALSE; - delete sl; - } - break; - //else unknown light source, doing nothing - case NO_LIGHT: - default: - { - if (light_type != NO_LIGHT) - g_warning("unknown light source %d", light_type); - for (i = 0; i < w*h; i++) { - data_o[4*i+3] = 255; - } - out->empty = false; - } + case DISTANT_LIGHT: + ink_cairo_surface_synthesize(out, + DiffuseDistantLight(input, light.distant, lighting_color, scale, diffuseConstant)); + break; + case POINT_LIGHT: + ink_cairo_surface_synthesize(out, + DiffusePointLight(input, light.point, lighting_color, trans, scale, diffuseConstant, x0, y0)); + break; + case SPOT_LIGHT: + ink_cairo_surface_synthesize(out, + DiffuseSpotLight(input, light.spot, lighting_color, trans, scale, diffuseConstant, x0, y0)); + break; + default: { + cairo_t *ct = cairo_create(out); + cairo_set_source_rgba(ct, 0,0,0,1); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); + cairo_destroy(ct); + } break; } - - //finishing + slot.set(_output, out); - //nr_pixblock_release(in); - //delete in; - return 0; + cairo_surface_destroy(out); } void FilterDiffuseLighting::area_enlarge(NRRectL &area, Geom::Affine const &trans) { // TODO: support kernelUnitLength - double scalex = std::fabs(trans[0]) + std::fabs(trans[1]); - double scaley = std::fabs(trans[2]) + std::fabs(trans[3]); - - //FIXME: no +2 should be there!... (noticable only for big scales at big zoom factor) - area.x0 -= (int)(scalex) + 2; - area.x1 += (int)(scalex) + 2; - area.y0 -= (int)(scaley) + 2; - area.y1 += (int)(scaley) + 2; -} -FilterTraits FilterDiffuseLighting::get_input_traits() { - return TRAIT_PARALLER; + // We expand the area by 1 in every direction to avoid artifacts on tile edges. + // However, it means that edge pixels will be incorrect. + area.x0 -= 1; + area.x1 += 1; + area.y0 -= 1; + area.y1 += 1; } } /* namespace Filters */ diff --git a/src/display/nr-filter-diffuselighting.h b/src/display/nr-filter-diffuselighting.h index f540bf4a5..6e39242f6 100644 --- a/src/display/nr-filter-diffuselighting.h +++ b/src/display/nr-filter-diffuselighting.h @@ -18,16 +18,22 @@ #include "display/nr-filter-primitive.h" #include "display/nr-filter-slot.h" #include "display/nr-filter-units.h" -#include "filters/distantlight.h" -#include "filters/pointlight.h" -#include "filters/spotlight.h" -#include "color.h" + +class SPFeDistantLight; +class SPFePointLight; +class SPFeSpotLight; namespace Inkscape { namespace Filters { class FilterDiffuseLighting : public FilterPrimitive { public: + FilterDiffuseLighting(); + static FilterPrimitive *create(); + virtual ~FilterDiffuseLighting(); + virtual void render_cairo(FilterSlot &slot); + virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); + union { SPFeDistantLight *distant; SPFePointLight *point; @@ -37,13 +43,6 @@ public: gdouble diffuseConstant; gdouble surfaceScale; guint32 lighting_color; - - FilterDiffuseLighting(); - static FilterPrimitive *create(); - virtual ~FilterDiffuseLighting(); - virtual int render(FilterSlot &slot, FilterUnits const &units); - virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); - virtual FilterTraits get_input_traits(); private: }; diff --git a/src/display/nr-filter-displacement-map.cpp b/src/display/nr-filter-displacement-map.cpp index d71a691ef..fdaf2c887 100644 --- a/src/display/nr-filter-displacement-map.cpp +++ b/src/display/nr-filter-displacement-map.cpp @@ -9,11 +9,11 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include "display/cairo-templates.h" +#include "display/cairo-utils.h" #include "display/nr-filter-displacement-map.h" #include "display/nr-filter-types.h" #include "display/nr-filter-units.h" -#include "libnr/nr-blit.h" -#include "libnr/nr-pixops.h" namespace Inkscape { namespace Filters { @@ -28,6 +28,7 @@ FilterPrimitive * FilterDisplacementMap::create() { FilterDisplacementMap::~FilterDisplacementMap() {} +#if 0 struct pixel_t { unsigned char channels[4]; inline unsigned char operator[](int c) const { return channels[c]; } @@ -147,7 +148,65 @@ static void performDisplacement(NRPixBlock const* texture, NRPixBlock const* map } } } +#endif + +struct Displace { + Displace(cairo_surface_t *texture, cairo_surface_t *map, + unsigned xch, unsigned ych, double scalex, double scaley) + : _texture(texture) + , _map(map) + , _xch(xch) + , _ych(ych) + , _scalex(scalex/255.0) + , _scaley(scaley/255.0) + {} + guint32 operator()(int x, int y) { + guint32 mappx = _map.pixelAt(x, y); + guint32 a = (mappx & 0xff000000) >> 24; + guint32 xpx = 0, ypx = 0; + double xtex = x, ytex = y; + if (a) { + guint32 xshift = _xch * 8, yshift = _ych * 8; + xpx = (mappx & (0xff << xshift)) >> xshift; + ypx = (mappx & (0xff << yshift)) >> yshift; + if (_xch != 3) xpx = unpremul_alpha(xpx, a); + if (_ych != 3) ypx = unpremul_alpha(ypx, a); + xtex += _scalex * (xpx - 127.5); + ytex += _scaley * (ypx - 127.5); + } + + if (xtex >= 0 && xtex < (_texture._w - 1) && + ytex >= 0 && ytex < (_texture._h - 1)) + { + return _texture.pixelAt(xtex, ytex); + } else { + return 0; + } + } +private: + SurfaceSynth _texture; + SurfaceSynth _map; + unsigned _xch, _ych; + double _scalex, _scaley; +}; + +void FilterDisplacementMap::render_cairo(FilterSlot &slot) +{ + cairo_surface_t *texture = slot.getcairo(_input); + cairo_surface_t *map = slot.getcairo(_input2); + cairo_surface_t *out = ink_cairo_surface_create_identical(texture); + + Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); + double scalex = scale * trans.expansionX(); + double scaley = scale * trans.expansionY(); + + ink_cairo_surface_synthesize(out, Displace(texture, map, Xchannel, Ychannel, scalex, scaley)); + + slot.set(_output, out); + cairo_surface_destroy(out); +} +/* int FilterDisplacementMap::render(FilterSlot &slot, FilterUnits const &units) { NRPixBlock *texture = slot.get(_input); NRPixBlock *map = slot.get(_input2); @@ -212,7 +271,7 @@ int FilterDisplacementMap::render(FilterSlot &slot, FilterUnits const &units) { out->empty = FALSE; slot.set(_output, out); return 0; -} +}*/ void FilterDisplacementMap::set_input(int slot) { _input = slot; @@ -233,8 +292,26 @@ void FilterDisplacementMap::set_channel_selector(int s, FilterDisplacementMapCha return; } - if (s == 0) Xchannel = channel; - if (s == 1) Ychannel = channel; + // channel numbering: + // a = 3, r = 2, g = 1, b = 0 + // this way we can get the component value using: + // component = (color & (ch*8)) >> (ch*8) + unsigned ch = 4; + switch (channel) { + case DISPLACEMENTMAP_CHANNEL_ALPHA: + ch = 3; break; + case DISPLACEMENTMAP_CHANNEL_RED: + ch = 2; break; + case DISPLACEMENTMAP_CHANNEL_GREEN: + ch = 1; break; + case DISPLACEMENTMAP_CHANNEL_BLUE: + ch = 0; break; + default: break; + } + if (ch == 4) return; + + if (s == 0) Xchannel = ch; + if (s == 1) Ychannel = ch; } void FilterDisplacementMap::area_enlarge(NRRectL &area, Geom::Affine const &trans) @@ -252,10 +329,6 @@ void FilterDisplacementMap::area_enlarge(NRRectL &area, Geom::Affine const &tran area.y1 += (int)(scaley)+2; } -FilterTraits FilterDisplacementMap::get_input_traits() { - return TRAIT_PARALLER; -} - } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-displacement-map.h b/src/display/nr-filter-displacement-map.h index 1dad1873a..aec4b7eb6 100644 --- a/src/display/nr-filter-displacement-map.h +++ b/src/display/nr-filter-displacement-map.h @@ -31,15 +31,13 @@ public: virtual void set_input(int input, int slot); virtual void set_scale(double s); virtual void set_channel_selector(int s, FilterDisplacementMapChannelSelector channel); - virtual int render(FilterSlot &slot, FilterUnits const &units); + virtual void render_cairo(FilterSlot &slot); virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); - virtual FilterTraits get_input_traits(); private: double scale; int _input2; - FilterDisplacementMapChannelSelector Xchannel; - FilterDisplacementMapChannelSelector Ychannel; + unsigned Xchannel, Ychannel; }; } /* namespace Filters */ diff --git a/src/display/nr-filter-flood.cpp b/src/display/nr-filter-flood.cpp index eb1cf13a6..a015d3f1f 100644 --- a/src/display/nr-filter-flood.cpp +++ b/src/display/nr-filter-flood.cpp @@ -14,10 +14,12 @@ # include "config.h" #endif +#include "display/cairo-utils.h" #include "display/nr-filter-flood.h" -#include "display/nr-filter-utils.h" +#include "display/nr-filter-slot.h" #include "svg/svg-icc-color.h" #include "svg/svg-color.h" +#include "color.h" namespace Inkscape { namespace Filters { @@ -32,67 +34,40 @@ FilterPrimitive * FilterFlood::create() { FilterFlood::~FilterFlood() {} -int FilterFlood::render(FilterSlot &slot, FilterUnits const &units) { -//g_message("rendering feflood"); - NRPixBlock *in = slot.get(_input); - if (!in) { - g_warning("Missing source image for feFlood (in=%d)", _input); - return 1; +void FilterFlood::render_cairo(FilterSlot &slot) +{ + cairo_surface_t *input = slot.getcairo(_input); + + double r = SP_RGBA32_R_F(color); + double g = SP_RGBA32_G_F(color); + double b = SP_RGBA32_B_F(color); + double a = opacity; + + #if ENABLE_LCMS + if (icc) { + guchar ru, gu, bu; + icc_color_to_sRGB(icc, &ru, &gu, &bu); + r = SP_COLOR_U_TO_F(ru); + g = SP_COLOR_U_TO_F(gu); + b = SP_COLOR_U_TO_F(bu); } + #endif - // Region being drawn on screen in screen coordinates. - int x0 = in->area.x0, y0 = in->area.y0; - int x1 = in->area.x1, y1 = in->area.y1; - int w = x1 - x0; - - // Set up pix block - NRPixBlock *out = new NRPixBlock; - nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8N, x0, y0, x1, y1, true); - unsigned char *out_data = NR_PIXBLOCK_PX(out); - - // Get RGBA values. - unsigned char r,g,b,a; - r = CLAMP_D_TO_U8((color >> 24) % 256); - g = CLAMP_D_TO_U8((color >> 16) % 256); - b = CLAMP_D_TO_U8((color >> 8) % 256); - a = CLAMP_D_TO_U8(opacity*255); - -#if ENABLE_LCMS - icc_color_to_sRGB(icc, &r, &g, &b); - //g_message("result: r:%d g:%d b:%d", r, g, b); -#endif //ENABLE_LCMS - - // Only fill primitive subregion - - // Get subregion in user units - Geom::Rect fp = filter_primitive_area( units ); - - // Need to convert to pixbuff units - Geom::Rect fp_pb = fp * units.get_matrix_user2pb(); - - // Make sure we are in pixbuff area - int fp_x0 = fp_pb.min()[Geom::X]; - int fp_x1 = fp_pb.max()[Geom::X]; - int fp_y0 = fp_pb.min()[Geom::Y]; - int fp_y1 = fp_pb.max()[Geom::Y]; - if( fp_x0 < x0 ) fp_x0 = x0; - if( fp_x1 > x1 ) fp_x1 = x1; - if( fp_y0 < y0 ) fp_y0 = y0; - if( fp_y1 > y1 ) fp_y1 = y1; - - // Do fill - for (int x=fp_x0; x < fp_x1; x++){ - for (int y=fp_y0; y < fp_y1; y++){ - out_data[ 4*((x - x0) + w*(y - y0)) ] = r; - out_data[ 4*((x - x0) + w*(y - y0)) + 1 ] = g; - out_data[ 4*((x - x0) + w*(y - y0)) + 2 ] = b; - out_data[ 4*((x - x0) + w*(y - y0)) + 3 ] = a; - } - } + cairo_surface_t *out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_COLOR_ALPHA); + cairo_t *ct = cairo_create(out); + cairo_set_source_rgba(ct, r, g, b, a); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); + cairo_destroy(ct); - out->empty = FALSE; slot.set(_output, out); - return 0; + cairo_surface_destroy(out); +} + +bool FilterFlood::can_handle_affine(Geom::Affine const &) +{ + // flood is a per-pixel primitive and is immutable under transformations + return true; } void FilterFlood::set_color(guint32 c) { diff --git a/src/display/nr-filter-flood.h b/src/display/nr-filter-flood.h index ebb7d4506..6db90d439 100644 --- a/src/display/nr-filter-flood.h +++ b/src/display/nr-filter-flood.h @@ -13,9 +13,8 @@ */ #include "display/nr-filter-primitive.h" -#include "display/nr-filter-slot.h" -#include "display/nr-filter-units.h" -#include "svg/svg-color.h" + +class SVGICCColor; namespace Inkscape { namespace Filters { @@ -25,11 +24,12 @@ public: FilterFlood(); static FilterPrimitive *create(); virtual ~FilterFlood(); - + + virtual void render_cairo(FilterSlot &slot); + virtual bool can_handle_affine(Geom::Affine const &); virtual void set_opacity(double o); virtual void set_color(guint32 c); virtual void set_icc(SVGICCColor *icc_color); - virtual int render(FilterSlot &slot, FilterUnits const &units); virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); private: double opacity; diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp index 9b83c8647..326c37160 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -27,12 +27,12 @@ #include "2geom/isnan.h" +#include "display/cairo-utils.h" #include "display/nr-filter-primitive.h" #include "display/nr-filter-gaussian.h" #include "display/nr-filter-types.h" #include "display/nr-filter-units.h" -#include "libnr/nr-blit.h" -#include "libnr/nr-pixblock.h" +#include "display/nr-filter-slot.h" #include <2geom/affine.h> #include "util/fixed_point.h" #include "preferences.h" @@ -82,24 +82,24 @@ static inline Tt round_cast(Ts v) { static Ts const rndoffset(.5); return static_cast<Tt>(v+rndoffset); } - +/* template<> inline unsigned char round_cast(double v) { // This (fast) rounding method is based on: // http://stereopsis.com/sree/fpu2006.html -#if G_BYTE_ORDER==G_LITTLE_ENDIAN
- double const dmr = 6755399441055744.0;
- v = v + dmr;
+#if G_BYTE_ORDER==G_LITTLE_ENDIAN + double const dmr = 6755399441055744.0; + v = v + dmr; return ((unsigned char*)&v)[0]; #elif G_BYTE_ORDER==G_BIG_ENDIAN - double const dmr = 6755399441055744.0;
- v = v + dmr;
+ double const dmr = 6755399441055744.0; + v = v + dmr; return ((unsigned char*)&v)[7]; #else static double const rndoffset(.5); - return static_cast<unsigned char>(v+rndoffset);
-#endif
-} + return static_cast<unsigned char>(v+rndoffset); +#endif +}*/ template<typename Tt, typename Ts> static inline Tt clip_round_cast(Ts const v) { @@ -142,7 +142,7 @@ FilterGaussian::~FilterGaussian() static int _effect_area_scr(double const deviation) { - return (int)std::ceil(deviation * 3.0); + return (int)std::ceil(std::fabs(deviation) * 3.0); } static void @@ -223,21 +223,6 @@ _effect_subsample_step_log2(double const deviation, int const quality) return stepsize_l2; } -/** - * Sanity check function for indexing pixblocks. - * Catches reading and writing outside the pixblock area. - * When enabled, decreases filter rendering speed massively. - */ -static inline void -_check_index(NRPixBlock const * const pb, int const location, int const line) -{ - if (false) { - int max_loc = pb->rs * (pb->area.y1 - pb->area.y0); - if (location < 0 || location >= max_loc) - g_warning("Location %d out of bounds (0 ... %d) at line %d", location, max_loc, line); - } -} - static void calcFilter(double const sigma, double b[N]) { assert(N==3); std::complex<double> const d1_org(1.40098, 1.00236); @@ -315,6 +300,14 @@ filter2D_IIR(PT *const dest, int const dstr1, int const dstr2, int const n1, int const n2, IIRValue const b[N+1], double const M[N*N], IIRValue *const tmpdata[], int const num_threads) { +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + static unsigned int const alpha_PC = PC-1; + #define PREMUL_ALPHA_LOOP for(unsigned int c=0; c<PC-1; ++c) +#else + static unsigned int const alpha_PC = 0; + #define PREMUL_ALPHA_LOOP for(unsigned int c=1; c<PC; ++c) +#endif + #if HAVE_OPENMP #pragma omp parallel for num_threads(num_threads) #else @@ -350,8 +343,8 @@ filter2D_IIR(PT *const dest, int const dstr1, int const dstr2, calcTriggsSdikaInitialization<PC>(M, u, iplus, iplus, b[0], v); dstimg -= dstr1; if ( PREMULTIPLIED_ALPHA ) { - dstimg[PC-1] = clip_round_cast<PT>(v[0][PC-1]); - for(unsigned int c=0; c<PC-1; c++) dstimg[c] = clip_round_cast_varmax<PT>(v[0][c], v[0][PC-1], dstimg[PC-1]); + dstimg[alpha_PC] = clip_round_cast<PT>(v[0][alpha_PC]); + PREMUL_ALPHA_LOOP dstimg[c] = clip_round_cast_varmax<PT>(v[0][c], v[0][alpha_PC], dstimg[alpha_PC]); } else { for(unsigned int c=0; c<PC; c++) dstimg[c] = clip_round_cast<PT>(v[0][c]); } @@ -365,8 +358,8 @@ filter2D_IIR(PT *const dest, int const dstr1, int const dstr2, } dstimg -= dstr1; if ( PREMULTIPLIED_ALPHA ) { - dstimg[PC-1] = clip_round_cast<PT>(v[0][PC-1]); - for(unsigned int c=0; c<PC-1; c++) dstimg[c] = clip_round_cast_varmax<PT>(v[0][c], v[0][PC-1], dstimg[PC-1]); + dstimg[alpha_PC] = clip_round_cast<PT>(v[0][alpha_PC]); + PREMUL_ALPHA_LOOP dstimg[c] = clip_round_cast_varmax<PT>(v[0][c], v[0][alpha_PC], dstimg[alpha_PC]); } else { for(unsigned int c=0; c<PC; c++) dstimg[c] = clip_round_cast<PT>(v[0][c]); } @@ -481,401 +474,196 @@ filter2D_FIR(PT *const dst, int const dstr1, int const dstr2, } } -template<typename PT, unsigned int PC> static void -downsample(PT *const dst, int const dstr1, int const dstr2, int const dn1, int const dn2, - PT const *const src, int const sstr1, int const sstr2, int const sn1, int const sn2, - int const step1_l2, int const step2_l2) +gaussian_pass_IIR(Geom::Dim2 d, double deviation, cairo_surface_t *src, cairo_surface_t *dest, + IIRValue **tmpdata, int num_threads) { - unsigned int const divisor_l2 = step1_l2+step2_l2; // step1*step2=2^(step1_l2+step2_l2) - unsigned int const round_offset = (1<<divisor_l2)/2; - int const step1 = 1<<step1_l2; - int const step2 = 1<<step2_l2; - int const step1_2 = step1/2; - int const step2_2 = step2/2; - for(int dc2 = 0 ; dc2 < dn2 ; dc2++) { - int const sc2_begin = (dc2<<step2_l2)-step2_2; - int const sc2_end = sc2_begin+step2; - for(int dc1 = 0 ; dc1 < dn1 ; dc1++) { - int const sc1_begin = (dc1<<step1_l2)-step1_2; - int const sc1_end = sc1_begin+step1; - unsigned int sum[PC]; - std::fill_n(sum, PC, 0); - for(int sc2 = sc2_begin ; sc2 < sc2_end ; sc2++) { - for(int sc1 = sc1_begin ; sc1 < sc1_end ; sc1++) { - for(unsigned int ch = 0 ; ch < PC ; ch++) { - sum[ch] += src[clip(sc2,0,sn2-1)*sstr2+clip(sc1,0,sn1-1)*sstr1+ch]; - } - } - } - for(unsigned int ch = 0 ; ch < PC ; ch++) { - dst[dc2*dstr2+dc1*dstr1+ch] = static_cast<PT>((sum[ch]+round_offset)>>divisor_l2); - } - } + // Filter variables + IIRValue b[N+1]; // scaling coefficient + filter coefficients (can be 10.21 fixed point) + double bf[N]; // computed filter coefficients + double M[N*N]; // matrix used for initialization procedure (has to be double) + + // Compute filter + calcFilter(deviation, bf); + for(size_t i=0; i<N; i++) bf[i] = -bf[i]; + b[0] = 1; // b[0] == alpha (scaling coefficient) + for(size_t i=0; i<N; i++) { + b[i+1] = bf[i]; + b[0] -= b[i+1]; } + + // Compute initialization matrix + calcTriggsSdikaM(bf, M); + + int stride = cairo_image_surface_get_stride(src); + int w = cairo_image_surface_get_width(src); + int h = cairo_image_surface_get_height(src); + if (d != Geom::X) std::swap(w, h); + + // Filter + switch (cairo_image_surface_get_format(src)) { + case CAIRO_FORMAT_A8: ///< Grayscale + filter2D_IIR<unsigned char,1,false>( + cairo_image_surface_get_data(dest), d == Geom::X ? 1 : stride, d == Geom::X ? stride : 1, + cairo_image_surface_get_data(src), d == Geom::X ? 1 : stride, d == Geom::X ? stride : 1, + w, h, b, M, tmpdata, num_threads); + break; + case CAIRO_FORMAT_ARGB32: ///< Premultiplied 8 bit RGBA + filter2D_IIR<unsigned char,4,true>( + cairo_image_surface_get_data(dest), d == Geom::X ? 4 : stride, d == Geom::X ? stride : 4, + cairo_image_surface_get_data(src), d == Geom::X ? 4 : stride, d == Geom::X ? stride : 4, + w, h, b, M, tmpdata, num_threads); + break; + default: + assert(false); + }; } -template<typename PT, unsigned int PC> static void -upsample(PT *const dst, int const dstr1, int const dstr2, unsigned int const dn1, unsigned int const dn2, - PT const *const src, int const sstr1, int const sstr2, unsigned int const sn1, unsigned int const sn2, - unsigned int const step1_l2, unsigned int const step2_l2) +gaussian_pass_FIR(Geom::Dim2 d, double deviation, cairo_surface_t *src, cairo_surface_t *dest, + int num_threads) { - assert(((sn1-1)<<step1_l2)>=dn1 && ((sn2-1)<<step2_l2)>=dn2); // The last pixel of the source image should fall outside the destination image - unsigned int const divisor_l2 = step1_l2+step2_l2; // step1*step2=2^(step1_l2+step2_l2) - unsigned int const round_offset = (1<<divisor_l2)/2; - unsigned int const step1 = 1<<step1_l2; - unsigned int const step2 = 1<<step2_l2; - for ( unsigned int sc2 = 0 ; sc2 < sn2-1 ; sc2++ ) { - unsigned int const dc2_begin = (sc2 << step2_l2); - unsigned int const dc2_end = std::min(dn2, dc2_begin+step2); - for ( unsigned int sc1 = 0 ; sc1 < sn1-1 ; sc1++ ) { - unsigned int const dc1_begin = (sc1 << step1_l2); - unsigned int const dc1_end = std::min(dn1, dc1_begin+step1); - for ( unsigned int byte = 0 ; byte < PC ; byte++) { - - // get 4 values at the corners of the pixel from src - PT a00 = src[sstr2* sc2 + sstr1* sc1 + byte]; - PT a10 = src[sstr2* sc2 + sstr1*(sc1+1) + byte]; - PT a01 = src[sstr2*(sc2+1) + sstr1* sc1 + byte]; - PT a11 = src[sstr2*(sc2+1) + sstr1*(sc1+1) + byte]; - - // initialize values for linear interpolation - unsigned int a0 = a00*step2/*+a01*0*/; - unsigned int a1 = a10*step2/*+a11*0*/; - - // iterate over the rectangle to be interpolated - for ( unsigned int dc2 = dc2_begin ; dc2 < dc2_end ; dc2++ ) { - - // prepare linear interpolation for this row - unsigned int a = a0*step1/*+a1*0*/+round_offset; - - for ( unsigned int dc1 = dc1_begin ; dc1 < dc1_end ; dc1++ ) { - - // simple linear interpolation - dst[dstr2*dc2 + dstr1*dc1 + byte] = static_cast<PT>(a>>divisor_l2); - - // compute a = a0*(ix-1)+a1*(xi+1)+round_offset - a = a - a0 + a1; - } - - // compute a0 = a00*(iy-1)+a01*(yi+1) and similar for a1 - a0 = a0 - a00 + a01; - a1 = a1 - a10 + a11; - } - } - } - } + int scr_len = _effect_area_scr(deviation); + // Filter kernel for x direction + FIRValue kernel[scr_len+1]; + _make_kernel(kernel, deviation); + + int stride = cairo_image_surface_get_stride(src); + int w = cairo_image_surface_get_width(src); + int h = cairo_image_surface_get_height(src); + if (d != Geom::X) std::swap(w, h); + + // Filter (x) + switch (cairo_image_surface_get_format(src)) { + case CAIRO_FORMAT_A8: ///< Grayscale + filter2D_FIR<unsigned char,1>( + cairo_image_surface_get_data(dest), d == Geom::X ? 1 : stride, d == Geom::X ? stride : 1, + cairo_image_surface_get_data(src), d == Geom::X ? 1 : stride, d == Geom::X ? stride : 1, + w, h, kernel, scr_len, num_threads); + break; + case CAIRO_FORMAT_ARGB32: ///< Premultiplied 8 bit RGBA + filter2D_FIR<unsigned char,4>( + cairo_image_surface_get_data(dest), d == Geom::X ? 4 : stride, d == Geom::X ? stride : 4, + cairo_image_surface_get_data(src), d == Geom::X ? 4 : stride, d == Geom::X ? stride : 4, + w, h, kernel, scr_len, num_threads); + break; + default: + assert(false); + }; } -int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units) +void FilterGaussian::render_cairo(FilterSlot &slot) { - // TODO: Meaningful return values? (If they're checked at all.) - - /* in holds the input pixblock */ - NRPixBlock *original_in = slot.get(_input); - - /* If to either direction, the standard deviation is zero or - * input image is not defined, - * a transparent black image should be returned. */ - if (_deviation_x <= 0 || _deviation_y <= 0 || original_in == NULL) { - NRPixBlock *src = original_in; - if (src == NULL) { - g_warning("Missing source image for feGaussianBlur (in=%d)", _input); - // A bit guessing here, but source graphic is likely to be of - // right size - src = slot.get(NR_FILTER_SOURCEGRAPHIC); - } - NRPixBlock *out = new NRPixBlock; - nr_pixblock_setup_fast(out, src->mode, src->area.x0, src->area.y0, - src->area.x1, src->area.y1, true); - if (out->size != NR_PIXBLOCK_SIZE_TINY && out->data.px != NULL) { - out->empty = false; - slot.set(_output, out); - } - return 0; + cairo_surface_t *in = slot.getcairo(_input); + if (!in) return; + + // zero deviation = transparent black as output + if (_deviation_x <= 0 || _deviation_y <= 0) { + cairo_surface_t *blank = ink_cairo_surface_create_identical(in); + slot.set(_output, blank); + cairo_surface_destroy(blank); + return; } - // Gaussian blur is defined to operate on non-premultiplied color values. - // So, convert the input first it uses non-premultiplied color values. - // And please note that this should not be done AFTER resampling, as resampling a non-premultiplied image - // does not simply yield a non-premultiplied version of the resampled premultiplied image!!! - NRPixBlock *in = original_in; - if (in->mode == NR_PIXBLOCK_MODE_R8G8B8A8N) { - in = nr_pixblock_new_fast(NR_PIXBLOCK_MODE_R8G8B8A8P, - original_in->area.x0, original_in->area.y0, - original_in->area.x1, original_in->area.y1, - false); - if (!in) { - // ran out of memory - return 0; - } - nr_blit_pixblock_pixblock(in, original_in); + Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); + + int w_orig = ink_cairo_surface_get_width(in); + int h_orig = ink_cairo_surface_get_height(in); + double deviation_x_orig = _deviation_x * trans.expansionX(); + double deviation_y_orig = _deviation_y * trans.expansionY(); + cairo_format_t fmt = cairo_image_surface_get_format(in); + int bytes_per_pixel = 0; + switch (fmt) { + case CAIRO_FORMAT_A8: + bytes_per_pixel = 1; break; + case CAIRO_FORMAT_ARGB32: + default: + bytes_per_pixel = 4; break; } - Geom::Affine trans = units.get_matrix_primitiveunits2pb(); - - // Some common constants - int const width_org = in->area.x1-in->area.x0, height_org = in->area.y1-in->area.y0; - double const deviation_x_org = _deviation_x * trans.expansionX(); - double const deviation_y_org = _deviation_y * trans.expansionY(); - int const PC = NR_PIXBLOCK_BPP(in); #if HAVE_OPENMP Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - int const NTHREADS = prefs->getIntLimited("/options/threading/numthreads", omp_get_num_procs(), 1, 256); + int threads = prefs->getIntLimited("/options/threading/numthreads", omp_get_num_procs(), 1, 256); #else - int const NTHREADS = 1; -#endif // HAVE_OPENMP + int threads = 1; +#endif - // Subsampling constants - int const quality = slot.get_blurquality(); - int const x_step_l2 = _effect_subsample_step_log2(deviation_x_org, quality); - int const y_step_l2 = _effect_subsample_step_log2(deviation_y_org, quality); - int const x_step = 1<<x_step_l2; - int const y_step = 1<<y_step_l2; - bool const resampling = x_step > 1 || y_step > 1; - int const width = resampling ? static_cast<int>(ceil(static_cast<double>(width_org)/x_step))+1 : width_org; - int const height = resampling ? static_cast<int>(ceil(static_cast<double>(height_org)/y_step))+1 : height_org; - double const deviation_x = deviation_x_org / x_step; - double const deviation_y = deviation_y_org / y_step; - int const scr_len_x = _effect_area_scr(deviation_x); - int const scr_len_y = _effect_area_scr(deviation_y); + int quality = slot.get_blurquality(); + int x_step = 1 << _effect_subsample_step_log2(deviation_x_orig, quality); + int y_step = 1 << _effect_subsample_step_log2(deviation_y_orig, quality); + bool resampling = x_step > 1 || y_step > 1; + int w_downsampled = resampling ? static_cast<int>(ceil(static_cast<double>(w_orig)/x_step))+1 : w_orig; + int h_downsampled = resampling ? static_cast<int>(ceil(static_cast<double>(h_orig)/y_step))+1 : h_orig; + double deviation_x = deviation_x_orig / x_step; + double deviation_y = deviation_y_orig / y_step; + int scr_len_x = _effect_area_scr(deviation_x); + int scr_len_y = _effect_area_scr(deviation_y); // Decide which filter to use for X and Y // This threshold was determined by trial-and-error for one specific machine, // so there's a good chance that it's not optimal. // Whatever you do, don't go below 1 (and preferrably not even below 2), as // the IIR filter gets unstable there. - bool const use_IIR_x = deviation_x > 3; - bool const use_IIR_y = deviation_y > 3; - - // new buffer for the subsampled output - NRPixBlock *out = new NRPixBlock; - nr_pixblock_setup_fast(out, in->mode, in->area.x0/x_step, in->area.y0/y_step, - in->area.x0/x_step+width, in->area.y0/y_step+height, true); - if (out->size != NR_PIXBLOCK_SIZE_TINY && out->data.px == NULL) { - // alas, we've accomplished a lot, but ran out of memory - so abort - if (in != original_in) nr_pixblock_free(in); - delete out; - return 0; - } + bool use_IIR_x = deviation_x > 3; + bool use_IIR_y = deviation_y > 3; + // Temporary storage for IIR filter // NOTE: This can be eliminated, but it reduces the precision a bit - IIRValue * tmpdata[NTHREADS]; - std::fill_n(tmpdata, NTHREADS, (IIRValue*)0); + IIRValue * tmpdata[threads]; + std::fill_n(tmpdata, threads, (IIRValue*)0); if ( use_IIR_x || use_IIR_y ) { - for(int i=0; i<NTHREADS; i++) { - tmpdata[i] = new IIRValue[std::max(width,height)*PC]; - if (tmpdata[i] == NULL) { - if (in != original_in) nr_pixblock_free(in); - nr_pixblock_release(out); - while(i-->0) { - delete[] tmpdata[i]; - } - delete out; - return 0; - } + for(int i = 0; i < threads; ++i) { + tmpdata[i] = new IIRValue[std::max(w_downsampled,h_downsampled)*bytes_per_pixel]; } } - // Resampling (if necessary), goes from in -> out (setting ssin to out if used) - NRPixBlock *ssin = in; - if ( resampling ) { - ssin = out; - // Downsample - switch(in->mode) { - case NR_PIXBLOCK_MODE_A8: ///< Grayscale - downsample<unsigned char,1>(NR_PIXBLOCK_PX(out), 1, out->rs, width, height, NR_PIXBLOCK_PX(in), 1, in->rs, width_org, height_org, x_step_l2, y_step_l2); - break; - case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB - downsample<unsigned char,3>(NR_PIXBLOCK_PX(out), 3, out->rs, width, height, NR_PIXBLOCK_PX(in), 3, in->rs, width_org, height_org, x_step_l2, y_step_l2); - break; - //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA - // downsample<unsigned char,4>(NR_PIXBLOCK_PX(out), 4, out->rs, width, height, NR_PIXBLOCK_PX(in), 4, in->rs, width_org, height_org, x_step_l2, y_step_l2); - // break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA - downsample<unsigned char,4>(NR_PIXBLOCK_PX(out), 4, out->rs, width, height, NR_PIXBLOCK_PX(in), 4, in->rs, width_org, height_org, x_step_l2, y_step_l2); - break; - default: - assert(false); - }; + cairo_surface_t *downsampled = NULL; + if (resampling) { + downsampled = cairo_surface_create_similar(in, cairo_surface_get_content(in), + w_downsampled, h_downsampled); + cairo_t *ct = cairo_create(downsampled); + cairo_scale(ct, static_cast<double>(w_downsampled)/w_orig, static_cast<double>(h_downsampled)/h_orig); + cairo_set_source_surface(ct, in, 0, 0); + cairo_paint(ct); + cairo_destroy(ct); + } else { + downsampled = ink_cairo_surface_copy(in); } + cairo_surface_flush(downsampled); - // Horizontal filtering, goes from ssin -> out (ssin might be equal to out, but these algorithms can be used in-place) - if (use_IIR_x) { - // Filter variables - IIRValue b[N+1]; // scaling coefficient + filter coefficients (can be 10.21 fixed point) - double bf[N]; // computed filter coefficients - double M[N*N]; // matrix used for initialization procedure (has to be double) - - // Compute filter (x) - calcFilter(deviation_x, bf); - for(size_t i=0; i<N; i++) bf[i] = -bf[i]; - b[0] = 1; // b[0] == alpha (scaling coefficient) - for(size_t i=0; i<N; i++) { - b[i+1] = bf[i]; - b[0] -= b[i+1]; + if (scr_len_x > 0) { + if (use_IIR_x) { + gaussian_pass_IIR(Geom::X, deviation_x, downsampled, downsampled, tmpdata, threads); + } else { + gaussian_pass_FIR(Geom::X, deviation_x, downsampled, downsampled, threads); } - - // Compute initialization matrix (x) - calcTriggsSdikaM(bf, M); - - // Filter (x) - switch(in->mode) { - case NR_PIXBLOCK_MODE_A8: ///< Grayscale - filter2D_IIR<unsigned char,1,false>(NR_PIXBLOCK_PX(out), 1, out->rs, NR_PIXBLOCK_PX(ssin), 1, ssin->rs, width, height, b, M, tmpdata, NTHREADS); - break; - case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB - filter2D_IIR<unsigned char,3,false>(NR_PIXBLOCK_PX(out), 3, out->rs, NR_PIXBLOCK_PX(ssin), 3, ssin->rs, width, height, b, M, tmpdata, NTHREADS); - break; - //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA - // filter2D_IIR<unsigned char,4,false>(NR_PIXBLOCK_PX(out), 4, out->rs, NR_PIXBLOCK_PX(ssin), 4, ssin->rs, width, height, b, M, tmpdata, NTHREADS); - // break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA - filter2D_IIR<unsigned char,4,true >(NR_PIXBLOCK_PX(out), 4, out->rs, NR_PIXBLOCK_PX(ssin), 4, ssin->rs, width, height, b, M, tmpdata, NTHREADS); - break; - default: - assert(false); - }; - } else if ( scr_len_x > 0 ) { // !use_IIR_x - // Filter kernel for x direction - FIRValue kernel[scr_len_x+1]; - _make_kernel(kernel, deviation_x); - - // Filter (x) - switch(in->mode) { - case NR_PIXBLOCK_MODE_A8: ///< Grayscale - filter2D_FIR<unsigned char,1>(NR_PIXBLOCK_PX(out), 1, out->rs, NR_PIXBLOCK_PX(ssin), 1, ssin->rs, width, height, kernel, scr_len_x, NTHREADS); - break; - case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB - filter2D_FIR<unsigned char,3>(NR_PIXBLOCK_PX(out), 3, out->rs, NR_PIXBLOCK_PX(ssin), 3, ssin->rs, width, height, kernel, scr_len_x, NTHREADS); - break; - //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA - // filter2D_FIR<unsigned char,4>(NR_PIXBLOCK_PX(out), 4, out->rs, NR_PIXBLOCK_PX(ssin), 4, ssin->rs, width, height, kernel, scr_len_x, NTHREADS); - // break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA - filter2D_FIR<unsigned char,4>(NR_PIXBLOCK_PX(out), 4, out->rs, NR_PIXBLOCK_PX(ssin), 4, ssin->rs, width, height, kernel, scr_len_x, NTHREADS); - break; - default: - assert(false); - }; - } else if ( out != ssin ) { // out can be equal to ssin if resampling is used - nr_blit_pixblock_pixblock(out, ssin); } - // Vertical filtering, goes from out -> out - if (use_IIR_y) { - // Filter variables - IIRValue b[N+1]; // scaling coefficient + filter coefficients (can be 10.21 fixed point) - double bf[N]; // computed filter coefficients - double M[N*N]; // matrix used for initialization procedure (has to be double) - - // Compute filter (y) - calcFilter(deviation_y, bf); - for(size_t i=0; i<N; i++) bf[i] = -bf[i]; - b[0] = 1; // b[0] == alpha (scaling coefficient) - for(size_t i=0; i<N; i++) { - b[i+1] = bf[i]; - b[0] -= b[i+1]; + if (scr_len_y > 0) { + if (use_IIR_y) { + gaussian_pass_IIR(Geom::Y, deviation_y, downsampled, downsampled, tmpdata, threads); + } else { + gaussian_pass_FIR(Geom::Y, deviation_y, downsampled, downsampled, threads); } - - // Compute initialization matrix (y) - calcTriggsSdikaM(bf, M); - - // Filter (y) - switch(in->mode) { - case NR_PIXBLOCK_MODE_A8: ///< Grayscale - filter2D_IIR<unsigned char,1,false>(NR_PIXBLOCK_PX(out), out->rs, 1, NR_PIXBLOCK_PX(out), out->rs, 1, height, width, b, M, tmpdata, NTHREADS); - break; - case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB - filter2D_IIR<unsigned char,3,false>(NR_PIXBLOCK_PX(out), out->rs, 3, NR_PIXBLOCK_PX(out), out->rs, 3, height, width, b, M, tmpdata, NTHREADS); - break; - //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA - // filter2D_IIR<unsigned char,4,false>(NR_PIXBLOCK_PX(out), out->rs, 4, NR_PIXBLOCK_PX(out), out->rs, 4, height, width, b, M, tmpdata, NTHREADS); - // break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA - filter2D_IIR<unsigned char,4,true >(NR_PIXBLOCK_PX(out), out->rs, 4, NR_PIXBLOCK_PX(out), out->rs, 4, height, width, b, M, tmpdata, NTHREADS); - break; - default: - assert(false); - }; - } else if ( scr_len_y > 0 ) { // !use_IIR_y - // Filter kernel for y direction - FIRValue kernel[scr_len_y+1]; - _make_kernel(kernel, deviation_y); - - // Filter (y) - switch(in->mode) { - case NR_PIXBLOCK_MODE_A8: ///< Grayscale - filter2D_FIR<unsigned char,1>(NR_PIXBLOCK_PX(out), out->rs, 1, NR_PIXBLOCK_PX(out), out->rs, 1, height, width, kernel, scr_len_y, NTHREADS); - break; - case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB - filter2D_FIR<unsigned char,3>(NR_PIXBLOCK_PX(out), out->rs, 3, NR_PIXBLOCK_PX(out), out->rs, 3, height, width, kernel, scr_len_y, NTHREADS); - break; - //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA - // filter2D_FIR<unsigned char,4>(NR_PIXBLOCK_PX(out), out->rs, 4, NR_PIXBLOCK_PX(out), out->rs, 4, height, width, kernel, scr_len_y, NTHREADS); - // break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA - filter2D_FIR<unsigned char,4>(NR_PIXBLOCK_PX(out), out->rs, 4, NR_PIXBLOCK_PX(out), out->rs, 4, height, width, kernel, scr_len_y, NTHREADS); - break; - default: - assert(false); - }; } - for(int i=0; i<NTHREADS; i++) { - delete[] tmpdata[i]; // deleting a nullptr has no effect, so this is safe - } - - // Upsampling, stores (the upsampled) out using slot.set(_output, ...) - if ( !resampling ) { - // No upsampling needed - out->empty = FALSE; - slot.set(_output, out); + cairo_surface_mark_dirty(downsampled); + if (resampling) { + cairo_surface_t *upsampled = cairo_surface_create_similar(downsampled, cairo_surface_get_content(downsampled), + w_orig, h_orig); + cairo_t *ct = cairo_create(upsampled); + cairo_scale(ct, static_cast<double>(w_orig)/w_downsampled, static_cast<double>(h_orig)/h_downsampled); + cairo_set_source_surface(ct, downsampled, 0, 0); + cairo_paint(ct); + cairo_destroy(ct); + + slot.set(_output, upsampled); + cairo_surface_destroy(upsampled); + cairo_surface_destroy(downsampled); } else { - // New buffer for the final output, same resolution as the in buffer - NRPixBlock *finalout = new NRPixBlock; - nr_pixblock_setup_fast(finalout, in->mode, in->area.x0, in->area.y0, - in->area.x1, in->area.y1, true); - if (finalout->size != NR_PIXBLOCK_SIZE_TINY && finalout->data.px == NULL) { - // alas, we've accomplished a lot, but ran out of memory - so abort - if (in != original_in) nr_pixblock_free(in); - nr_pixblock_release(out); - delete out; - return 0; - } - - // Upsample - switch(in->mode) { - case NR_PIXBLOCK_MODE_A8: ///< Grayscale - upsample<unsigned char,1>(NR_PIXBLOCK_PX(finalout), 1, finalout->rs, width_org, height_org, NR_PIXBLOCK_PX(out), 1, out->rs, width, height, x_step_l2, y_step_l2); - break; - case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB - upsample<unsigned char,3>(NR_PIXBLOCK_PX(finalout), 3, finalout->rs, width_org, height_org, NR_PIXBLOCK_PX(out), 3, out->rs, width, height, x_step_l2, y_step_l2); - break; - //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA - // upsample<unsigned char,4>(NR_PIXBLOCK_PX(finalout), 4, finalout->rs, width_org, height_org, NR_PIXBLOCK_PX(out), 4, out->rs, width, height, x_step_l2, y_step_l2); - // break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA - upsample<unsigned char,4>(NR_PIXBLOCK_PX(finalout), 4, finalout->rs, width_org, height_org, NR_PIXBLOCK_PX(out), 4, out->rs, width, height, x_step_l2, y_step_l2); - break; - default: - assert(false); - }; - - // We don't need the out buffer anymore - nr_pixblock_release(out); - delete out; - - // The final out buffer gets returned - finalout->empty = FALSE; - slot.set(_output, finalout); + slot.set(_output, downsampled); + cairo_surface_destroy(downsampled); } - - // If we downsampled the input, clean up the downsampled data - if (in != original_in) nr_pixblock_free(in); - - return 0; } void FilterGaussian::area_enlarge(NRRectL &area, Geom::Affine const &trans) @@ -891,8 +679,13 @@ void FilterGaussian::area_enlarge(NRRectL &area, Geom::Affine const &trans) area.y1 += area_max; } -FilterTraits FilterGaussian::get_input_traits() { - return TRAIT_PARALLER; +bool FilterGaussian::can_handle_affine(Geom::Affine const &) +{ + // Previously we tried to be smart and return true for rotations. + // However, the transform passed here is NOT the total transform + // from filter user space to screen. + // TODO: fix this, or replace can_handle_affine() with isotropic(). + return false; } void FilterGaussian::set_deviation(double deviation) diff --git a/src/display/nr-filter-gaussian.h b/src/display/nr-filter-gaussian.h index 87d74ac63..811502016 100644 --- a/src/display/nr-filter-gaussian.h +++ b/src/display/nr-filter-gaussian.h @@ -14,12 +14,8 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "display/nr-filter-primitive.h" -#include "display/nr-filter-slot.h" -#include "display/nr-filter-units.h" -#include "libnr/nr-pixblock.h" #include <2geom/forward.h> -#include "libnr/nr-rect-l.h" +#include "display/nr-filter-primitive.h" enum { BLUR_QUALITY_BEST = 2, @@ -38,9 +34,9 @@ public: static FilterPrimitive *create(); virtual ~FilterGaussian(); - virtual int render(FilterSlot &slot, FilterUnits const &units); + virtual void render_cairo(FilterSlot &slot); virtual void area_enlarge(NRRectL &area, Geom::Affine const &m); - virtual FilterTraits get_input_traits(); + virtual bool can_handle_affine(Geom::Affine const &m); /** * Set the standard deviation value for gaussian blur. Deviation along diff --git a/src/display/nr-filter-getalpha.cpp b/src/display/nr-filter-getalpha.cpp deleted file mode 100644 index 7b5e2a101..000000000 --- a/src/display/nr-filter-getalpha.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Functions for extracting alpha channel from NRPixBlocks. - * - * Author: - * Niko Kiirala <niko@kiirala.com> - * - * Copyright (C) 2007 Niko Kiirala - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "display/nr-filter-getalpha.h" -#include "libnr/nr-blit.h" -#include "libnr/nr-pixblock.h" - -namespace Inkscape { -namespace Filters { - -NRPixBlock *filter_get_alpha(NRPixBlock *src) -{ - NRPixBlock *dst = new NRPixBlock; - nr_pixblock_setup_fast(dst, NR_PIXBLOCK_MODE_R8G8B8A8P, - src->area.x0, src->area.y0, - src->area.x1, src->area.y1, false); - if (!dst || (dst->size != NR_PIXBLOCK_SIZE_TINY && dst->data.px == NULL)) { - g_warning("Memory allocation failed in filter_get_alpha"); - delete dst; - return NULL; - } - nr_blit_pixblock_pixblock(dst, src); - - unsigned char *data = NR_PIXBLOCK_PX(dst); - int end = dst->rs * (dst->area.y1 - dst->area.y0); - for (int i = 0 ; i < end ; i += 4) { - data[i + 0] = 0; - data[i + 1] = 0; - data[i + 2] = 0; - } - dst->empty = false; - - return dst; -} - -} /* 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 : diff --git a/src/display/nr-filter-getalpha.h b/src/display/nr-filter-getalpha.h deleted file mode 100644 index e279494b1..000000000 --- a/src/display/nr-filter-getalpha.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef __NR_FILTER_GETALPHA_H__ -#define __NR_FILTER_GETALPHA_H__ - -/* - * Functions for extracting alpha channel from NRPixBlocks. - * - * Author: - * Niko Kiirala <niko@kiirala.com> - * - * Copyright (C) 2007 Niko Kiirala - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "libnr/nr-pixblock.h" - -namespace Inkscape { -namespace Filters { - -NRPixBlock *filter_get_alpha(NRPixBlock *src); - -} /* namespace Filters */ -} /* namespace Inkscape */ - -#endif /* __NR_FILTER_GETALPHA_H__ */ -/* - 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 : diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index 9ecec69bf..0cb7901b3 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -12,25 +12,23 @@ */ #include "document.h" #include "sp-item.h" +#include "display/cairo-utils.h" #include "display/nr-arena.h" #include "display/nr-arena-item.h" #include "display/nr-filter.h" #include "display/nr-filter-image.h" #include "display/nr-filter-units.h" -#include "libnr/nr-compose-transform.h" #include "libnr/nr-rect-l.h" -#include "preferences.h" -#include "svg/svg-length.h" -#include "enums.h" namespace Inkscape { namespace Filters { -FilterImage::FilterImage() : - SVGElem(0), - document(0), - feImageHref(0), - image_pixbuf(0) +FilterImage::FilterImage() + : SVGElem(0) + , document(0) + , feImageHref(0) + , image_surface(0) + , broken_ref(false) { } FilterPrimitive * FilterImage::create() { @@ -39,76 +37,95 @@ FilterPrimitive * FilterImage::create() { FilterImage::~FilterImage() { - if (feImageHref) g_free(feImageHref); + if (feImageHref) + g_free(feImageHref); } -int FilterImage::render(FilterSlot &slot, FilterUnits const &units) { - if (!feImageHref) return 0; - - NRPixBlock* pb = NULL; - bool free_pb_on_exit = false; - - if(from_element){ - if (!SVGElem) return 0; - - // prep the document +void FilterImage::render_cairo(FilterSlot &slot) +{ + if (!feImageHref) + return; + + //cairo_surface_t *input = slot.getcairo(_input); + + Geom::Affine m = slot.get_units().get_matrix_user2filterunits().inverse(); + Geom::Point bbox_00 = Geom::Point(0,0) * m; + Geom::Point bbox_w0 = Geom::Point(1,0) * m; + Geom::Point bbox_0h = Geom::Point(0,1) * m; + double bbox_width = Geom::distance(bbox_00, bbox_w0); + double bbox_height = Geom::distance(bbox_00, bbox_0h); + + + // feImage is suppose to use the same parameters as a normal SVG image. + // If a width or height is set to zero, the image is not suppose to be displayed. + // This does not seem to be what Firefox or Opera does, nor does the W3C displacement + // filter test expect this behavior. If the width and/or height are zero, we use + // the width and height of the object bounding box. + if( feImageWidth == 0 ) feImageWidth = bbox_width; + if( feImageHeight == 0 ) feImageHeight = bbox_height; + + if (from_element) { + if (!SVGElem) return; + + // TODO: do not recreate the rendering tree every time + // TODO: the entire thing is a hack, we should give filter primitives an "update" method + // like the one for NRArenaItems document->ensureUpToDate(); + NRArena* arena = NRArena::create(); + Geom::OptRect optarea = SVGElem->getBounds(Geom::identity()); + if (!optarea) return; + unsigned const key = SPItem::display_key_new(1); NRArenaItem* ai = SVGElem->invoke_show(arena, key, SP_ITEM_SHOW_DISPLAY); + if (!ai) { g_warning("feImage renderer: error creating NRArenaItem for SVG Element"); nr_object_unref((NRObject *) arena); - return 0; + return; } - pb = new NRPixBlock; - free_pb_on_exit = true; - - Geom::OptRect area = SVGElem->getBounds(Geom::identity()); - - NRRectL rect; - rect.x0=area->min()[Geom::X]; - rect.x1=area->max()[Geom::X]; - rect.y0=area->min()[Geom::Y]; - rect.y1=area->max()[Geom::Y]; - - width = (int)(rect.x1-rect.x0); - height = (int)(rect.y1-rect.y0); - rowstride = 4*width; - has_alpha = true; - - if (image_pixbuf) g_free(image_pixbuf); - image_pixbuf = g_try_new(unsigned char, 4L * width * height); - if(image_pixbuf != NULL) - { - memset(image_pixbuf, 0x00, 4 * width * height); - - NRGC gc(NULL); - /* Update to renderable state */ - double sf = 1.0; - Geom::Affine t(Geom::Scale(sf, sf)); - nr_arena_item_set_transform(ai, &t); - gc.transform.setIdentity(); - nr_arena_item_invoke_update( ai, NULL, &gc, - NR_ARENA_ITEM_STATE_ALL, - NR_ARENA_ITEM_STATE_NONE ); - nr_pixblock_setup_extern(pb, NR_PIXBLOCK_MODE_R8G8B8A8N, - (int)rect.x0, (int)rect.y0, (int)rect.x1, (int)rect.y1, - image_pixbuf, 4 * width, FALSE, FALSE ); - - nr_arena_item_invoke_render(NULL, ai, &rect, pb, NR_ARENA_ITEM_RENDER_NO_CACHE); - } - else - { - g_warning("FilterImage::render: not enough memory to create pixel buffer. Need %ld.", 4L * width * height); - } + Geom::Rect area = *optarea; + Geom::Affine pu2pb = slot.get_units().get_matrix_primitiveunits2pb(); + + double scaleX = feImageWidth / area.width(); + double scaleY = feImageHeight / area.height(); + + Geom::Rect sa = slot.get_slot_area(); + cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + sa.width(), sa.height()); + cairo_t *ct = cairo_create(out); + cairo_translate(ct, -sa.min()[Geom::X], -sa.min()[Geom::Y]); + ink_cairo_transform(ct, pu2pb); // we are now in primitive units + cairo_translate(ct, feImageX, feImageY); + cairo_scale(ct, scaleX, scaleY); + + NRRectL render_rect; + render_rect.x0 = floor(area.left()); + render_rect.y0 = floor(area.top()); + render_rect.x1 = ceil(area.right()); + render_rect.y1 = ceil(area.bottom()); + cairo_translate(ct, render_rect.x0, render_rect.y0); + + // Update to renderable state + NRGC gc(NULL); + Geom::Affine t = Geom::identity(); + nr_arena_item_set_transform(ai, &t); + gc.transform.setIdentity(); + nr_arena_item_invoke_update(ai, NULL, &gc, + NR_ARENA_ITEM_STATE_ALL, + NR_ARENA_ITEM_STATE_NONE); + nr_arena_item_invoke_render(ct, ai, &render_rect, NULL, NR_ARENA_ITEM_RENDER_NO_CACHE); SVGElem->invoke_hide(key); - nr_object_unref((NRObject *) arena); - } + nr_object_unref((NRObject*) arena); + slot.set(_output, out); + cairo_surface_destroy(out); + return; + } - if (!image_pixbuf){ + if (!image && !broken_ref) { + broken_ref = true; try { /* TODO: If feImageHref is absolute, then use that (preferably handling the * case that it's not a file URI). Otherwise, go up the tree looking @@ -127,190 +144,92 @@ int FilterImage::render(FilterSlot &slot, FilterUnits const &units) { if ( !g_file_test( fullname, G_FILE_TEST_EXISTS ) ) { // Should display Broken Image png. g_warning("FilterImage::render: Can not find: %s", feImageHref ); + return; } image = Gdk::Pixbuf::create_from_file(fullname); if( fullname != feImageHref ) g_free( fullname ); } catch (const Glib::FileError & e) { - g_warning("caught Glib::FileError in FilterImage::render %i", e.code() ); - return 0; + g_warning("caught Glib::FileError in FilterImage::render: %s", e.what().data() ); + return; } catch (const Gdk::PixbufError & e) { - g_warning("Gdk::PixbufError in FilterImage::render: %i", e.code() ); - return 0; + g_warning("Gdk::PixbufError in FilterImage::render: %s", e.what().data() ); + return; } - if ( !image ) return 0; + if ( !image ) return; - // Native size of image - width = image->get_width(); - height = image->get_height(); - rowstride = image->get_rowstride(); - image_pixbuf = image->get_pixels(); - has_alpha = image->get_has_alpha(); - } + broken_ref = false; - // Viewport is filter primitive area (in user coordinates). - Geom::Rect vp = filter_primitive_area( units ); - double feImageX = vp.min()[Geom::X]; - double feImageY = vp.min()[Geom::Y]; - double feImageWidth = vp.width(); - double feImageHeight = vp.height(); - - // Now that we have the viewport, we must map image inside. - // Partially copied from sp-image.cpp. - - // Do nothing if preserveAspectRatio is "none". - if( aspect_align != SP_ASPECT_NONE ) { - - // Check aspect ratio of image vs. viewport - double feAspect = feImageHeight/feImageWidth; - double aspect = (double)height/(double)width; - bool ratio = (feAspect < aspect); - - double ax, ay; // Align side - switch( aspect_align ) { - case SP_ASPECT_XMIN_YMIN: - ax = 0.0; - ay = 0.0; - break; - case SP_ASPECT_XMID_YMIN: - ax = 0.5; - ay = 0.0; - break; - case SP_ASPECT_XMAX_YMIN: - ax = 1.0; - ay = 0.0; - break; - case SP_ASPECT_XMIN_YMID: - ax = 0.0; - ay = 0.5; - break; - case SP_ASPECT_XMID_YMID: - ax = 0.5; - ay = 0.5; - break; - case SP_ASPECT_XMAX_YMID: - ax = 1.0; - ay = 0.5; - break; - case SP_ASPECT_XMIN_YMAX: - ax = 0.0; - ay = 1.0; - break; - case SP_ASPECT_XMID_YMAX: - ax = 0.5; - ay = 1.0; - break; - case SP_ASPECT_XMAX_YMAX: - ax = 1.0; - ay = 1.0; - break; - default: - ax = 0.0; - ay = 0.0; - break; + bool has_alpha = image->get_has_alpha(); + if (!has_alpha) { + image = image->add_alpha(false, 0, 0, 0); } - if( aspect_clip == SP_ASPECT_SLICE ) { - // image clipped by viewbox - - if( ratio ) { - // clip top/bottom - feImageY -= ay * (feImageWidth * aspect - feImageHeight); - feImageHeight = feImageWidth * aspect; - } else { - // clip sides - feImageX -= ax * (feImageHeight / aspect - feImageWidth); - feImageWidth = feImageHeight / aspect; - } + // Native size of image + //width = image->get_width(); + //height = image->get_height(); + //rowstride = image->get_rowstride(); - } else { - // image fits into viewbox - - if( ratio ) { - // fit to height - feImageX += ax * (feImageWidth - feImageHeight / aspect ); - feImageWidth = feImageHeight / aspect; - } else { - // fit to width - feImageY += ay * (feImageHeight - feImageWidth * aspect); - feImageHeight = feImageWidth * aspect; - } - } - } + convert_pixbuf_normal_to_argb32(image->gobj()); - // Set up user coordinates to pix block transforms - double scaleX = width/feImageWidth; - double scaleY = height/feImageHeight; - Geom::Affine unit_trans = units.get_matrix_user2pb().inverse(); - - // Region being drawn on screen. Corresponds to Filter Region in current screen coordinates. - // Note, that the screen is refreshed in horizontal slices with y-axis inverted. - NRPixBlock *in = slot.get(_input); - if (!in) { - g_warning("Missing source image for feImage (in=%d)", _input); - return 1; - } - int x0 = in->area.x0, y0 = in->area.y0; - int x1 = in->area.x1, y1 = in->area.y1; - int w = x1 - x0; - - Geom::Affine d2s = Geom::Translate(x0, y0) * unit_trans * Geom::Translate(-feImageX,-feImageY) * Geom::Scale(scaleX, scaleY); - - // Set up pix block - NRPixBlock *out = new NRPixBlock; - nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8P, x0, y0, x1, y1, true); - unsigned char *out_data = NR_PIXBLOCK_PX(out); - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - int nr_arena_image_x_sample = prefs->getInt("/options/bitmapoversample/value", 1); - int nr_arena_image_y_sample = nr_arena_image_x_sample; - - - if (has_alpha) { - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM(out_data, x1-x0, y1-y0, 4*w, image_pixbuf, width, height, rowstride, d2s, 255, nr_arena_image_x_sample, nr_arena_image_y_sample); - } else { - for (int x=x0; x < x1; x++){ - for (int y=y0; y < y1; y++){ - //TODO: use interpolation - // Temporarily add 0.5 so we sample center of "cell" - double indexX = scaleX * (((x+0.5) * unit_trans[0] + unit_trans[4]) - feImageX); - double indexY = scaleY * (((y+0.5) * unit_trans[3] + unit_trans[5]) - feImageY); - - // coordx == 0 and coordy == 0 must be included, but we protect - // against negative numbers which round up to 0 with (int). - int coordx = ( indexX >= 0 ? int( indexX ) : -1 ); - int coordy = ( indexY >= 0 ? int( indexY ) : -1 ); - if (coordx >= 0 && coordx < width && coordy >= 0 && coordy < height){ - out_data[4*((x - x0)+w*(y - y0)) ] = (unsigned char) image_pixbuf[3*coordx + rowstride*coordy ]; //Red - out_data[4*((x - x0)+w*(y - y0)) + 1] = (unsigned char) image_pixbuf[3*coordx + rowstride*coordy + 1]; //Green - out_data[4*((x - x0)+w*(y - y0)) + 2] = (unsigned char) image_pixbuf[3*coordx + rowstride*coordy + 2]; //Blue - out_data[4*((x - x0)+w*(y - y0)) + 3] = 255; //Alpha - } - } - } - } - if (free_pb_on_exit) { - nr_pixblock_release(pb); - delete pb; + image_surface = cairo_image_surface_create_for_data(image->get_pixels(), + CAIRO_FORMAT_ARGB32, image->get_width(), image->get_height(), image->get_rowstride()); } - out->empty = FALSE; + Geom::Rect sa = slot.get_slot_area(); + cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + sa.width(), sa.height()); + + cairo_t *ct = cairo_create(out); + cairo_translate(ct, -sa.min()[Geom::X], -sa.min()[Geom::Y]); + // now ct is in pb coordinates + ink_cairo_transform(ct, slot.get_units().get_matrix_primitiveunits2pb()); + // now ct is in the coordinates of feImageX etc. + + // TODO: add preserveAspectRatio support here + + double scaleX = feImageWidth / image->get_width(); + double scaleY = feImageHeight / image->get_height(); + + cairo_translate(ct, feImageX, feImageY); + cairo_scale(ct, scaleX, scaleY); + cairo_set_source_surface(ct, image_surface, 0, 0); + cairo_paint(ct); + cairo_destroy(ct); + slot.set(_output, out); - return 0; +} + +bool FilterImage::can_handle_affine(Geom::Affine const &) +{ + return true; } void FilterImage::set_href(const gchar *href){ if (feImageHref) g_free (feImageHref); feImageHref = (href) ? g_strdup (href) : NULL; + + if (image_surface) { + cairo_surface_destroy(image_surface); + } + image.reset(); + broken_ref = false; } void FilterImage::set_document(SPDocument *doc){ document = doc; } +void FilterImage::set_region(SVGLength x, SVGLength y, SVGLength width, SVGLength height) { + feImageX=x.computed; + feImageY=y.computed; + feImageWidth=width.computed; + feImageHeight=height.computed; +} + void FilterImage::set_align( unsigned int align ) { aspect_align = align; } @@ -319,10 +238,6 @@ void FilterImage::set_clip( unsigned int clip ) { aspect_clip = clip; } -FilterTraits FilterImage::get_input_traits() { - return TRAIT_PARALLER; -} - } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-image.h b/src/display/nr-filter-image.h index ecbc9597d..0651109ec 100644 --- a/src/display/nr-filter-image.h +++ b/src/display/nr-filter-image.h @@ -27,10 +27,11 @@ public: static FilterPrimitive *create(); virtual ~FilterImage(); - virtual int render(FilterSlot &slot, FilterUnits const &units); - virtual FilterTraits get_input_traits(); + virtual void render_cairo(FilterSlot &slot); + virtual bool can_handle_affine(Geom::Affine const &); void set_document( SPDocument *document ); void set_href(const gchar *href); + void set_region(SVGLength x, SVGLength y, SVGLength width, SVGLength height); void set_align( unsigned int align ); void set_clip( unsigned int clip ); bool from_element; @@ -39,12 +40,11 @@ public: private: SPDocument *document; gchar *feImageHref; - guint8* image_pixbuf; Glib::RefPtr<Gdk::Pixbuf> image; - int width, height, rowstride; - unsigned int aspect_align : 4; - unsigned int aspect_clip : 1; - bool has_alpha; + cairo_surface_t *image_surface; + float feImageX, feImageY, feImageWidth, feImageHeight; + unsigned int aspect_align, aspect_clip; + bool broken_ref; }; } /* namespace Filters */ diff --git a/src/display/nr-filter-merge.cpp b/src/display/nr-filter-merge.cpp index 971dcb80f..51d3975cb 100644 --- a/src/display/nr-filter-merge.cpp +++ b/src/display/nr-filter-merge.cpp @@ -9,28 +9,11 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <cmath> #include <vector> - -#include "2geom/isnan.h" -#include "filters/merge.h" +#include "display/cairo-utils.h" #include "display/nr-filter-merge.h" -#include "display/nr-filter-pixops.h" #include "display/nr-filter-slot.h" -#include "display/nr-filter-units.h" #include "display/nr-filter-utils.h" -#include "libnr/nr-blit.h" -#include "libnr/nr-pixblock.h" -#include "libnr/nr-pixops.h" - -inline void -composite_over(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - r[0] = a[0] + NR_NORMALIZE_21(b[0] * (255 - a[3])); - r[1] = a[1] + NR_NORMALIZE_21(b[1] * (255 - a[3])); - r[2] = a[2] + NR_NORMALIZE_21(b[2] * (255 - a[3])); - r[3] = a[3] + NR_NORMALIZE_21(b[3] * (255 - a[3])); -} namespace Inkscape { namespace Filters { @@ -46,70 +29,42 @@ FilterPrimitive * FilterMerge::create() { FilterMerge::~FilterMerge() {} -int FilterMerge::render(FilterSlot &slot, FilterUnits const &/*units*/) { - NRPixBlock *in[_input_image.size()]; - NRPixBlock *original_in[_input_image.size()]; - - for (unsigned int i = 0 ; i < _input_image.size() ; i++) { - in[i] = slot.get(_input_image[i]); - original_in[i] = in[i]; - } - - NRPixBlock *out; - - // Bail out if one of source images is missing - for (unsigned int i = 0 ; i < _input_image.size() ; i++) { - bool missing = false; - if (!in[i]) { - g_warning("Missing source image for feMerge (number=%d slot=%d)", i, _input_image[i]); - missing = true; - } - if (missing) return 1; - } - - out = new NRPixBlock; - NRRectL out_area = in[0]->area; - for (unsigned int i = 1 ; i < _input_image.size() ; i++) { - nr_rect_l_union(&out_area, &out_area, &in[i]->area); - } - nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8P, - out_area.x0, out_area.y0, out_area.x1, out_area.y1, - true); - - // Merge is defined for premultiplied RGBA values, thus convert them to - // that format before blending - for (unsigned int i = 0 ; i < _input_image.size() ; i++) { - if (in[i]->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) { - in[i] = new NRPixBlock; - nr_pixblock_setup_fast(in[i], NR_PIXBLOCK_MODE_R8G8B8A8P, - original_in[i]->area.x0, - original_in[i]->area.y0, - original_in[i]->area.x1, - original_in[i]->area.y1, - false); - nr_blit_pixblock_pixblock(in[i], original_in[i]); +void FilterMerge::render_cairo(FilterSlot &slot) +{ + if (_input_image.size() == 0) return; + + // output is RGBA if at least one input is RGBA + bool rgba32 = false; + cairo_surface_t *out = NULL; + for (std::vector<int>::iterator i = _input_image.begin(); i != _input_image.end(); ++i) { + cairo_surface_t *in = slot.getcairo(*i); + if (cairo_surface_get_content(in) == CAIRO_CONTENT_COLOR_ALPHA) { + out = ink_cairo_surface_create_identical(in); + rgba32 = true; + break; } } - /* pixops_mix is defined in display/nr-filter-pixops.h - * It mixes the two input images with the function given as template - * and places the result in output image. - */ - for (unsigned int i = 0 ; i < _input_image.size() ; i++) { - pixops_mix<composite_over>(*out, *in[i], *out); + if (!rgba32) { + out = ink_cairo_surface_create_identical(slot.getcairo(_input_image[0])); } + cairo_t *out_ct = cairo_create(out); - for (unsigned int i = 0 ; i < _input_image.size() ; i++) { - if (in[i] != original_in[i]) { - nr_pixblock_release(in[i]); - delete in[i]; - } + for (std::vector<int>::iterator i = _input_image.begin(); i != _input_image.end(); ++i) { + cairo_surface_t *in = slot.getcairo(*i); + cairo_set_source_surface(out_ct, in, 0, 0); + cairo_paint(out_ct); } - out->empty = FALSE; + cairo_destroy(out_ct); slot.set(_output, out); + cairo_surface_destroy(out); +} - return 0; +bool FilterMerge::can_handle_affine(Geom::Affine const &) +{ + // Merge is a per-pixel primitive and is immutable under transformations + return true; } void FilterMerge::set_input(int slot) { diff --git a/src/display/nr-filter-merge.h b/src/display/nr-filter-merge.h index 715f20d83..263fc8026 100644 --- a/src/display/nr-filter-merge.h +++ b/src/display/nr-filter-merge.h @@ -13,11 +13,7 @@ */ #include <vector> - -#include "filters/merge.h" #include "display/nr-filter-primitive.h" -#include "display/nr-filter-slot.h" -#include "display/nr-filter-units.h" namespace Inkscape { namespace Filters { @@ -28,7 +24,8 @@ public: static FilterPrimitive *create(); virtual ~FilterMerge(); - virtual int render(FilterSlot &slot, FilterUnits const &units); + virtual void render_cairo(FilterSlot &); + virtual bool can_handle_affine(Geom::Affine const &); virtual void set_input(int input); virtual void set_input(int input, int slot); diff --git a/src/display/nr-filter-morphology.cpp b/src/display/nr-filter-morphology.cpp index ceb2a2b9d..c79667d3e 100644 --- a/src/display/nr-filter-morphology.cpp +++ b/src/display/nr-filter-morphology.cpp @@ -10,9 +10,12 @@ */ #include <cmath> +#include <algorithm> +#include "display/cairo-templates.h" +#include "display/cairo-utils.h" #include "display/nr-filter-morphology.h" +#include "display/nr-filter-slot.h" #include "display/nr-filter-units.h" -#include "libnr/nr-blit.h" namespace Inkscape { namespace Filters { @@ -28,94 +31,126 @@ FilterPrimitive * FilterMorphology::create() { FilterMorphology::~FilterMorphology() {} -int FilterMorphology::render(FilterSlot &slot, FilterUnits const &units) { - NRPixBlock *in = slot.get(_input); - if (!in) { - g_warning("Missing source image for feMorphology (in=%d)", _input); - return 1; - } - - NRPixBlock *out = new NRPixBlock; - - // this primitive is defined for premultiplied RGBA values, - // thus convert them to that format - bool free_in_on_exit = false; - if (in->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) { - NRPixBlock *original_in = in; - in = new NRPixBlock; - nr_pixblock_setup_fast(in, NR_PIXBLOCK_MODE_R8G8B8A8P, - original_in->area.x0, original_in->area.y0, - original_in->area.x1, original_in->area.y1, - true); - nr_blit_pixblock_pixblock(in, original_in); - free_in_on_exit = true; - } +enum MorphologyOp { + ERODE, + DILATE +}; + +namespace { + +/* This performs one "half" of the morphology operation by calculating + * the componentwise extreme in the specified axis with the given radius. + * Performing the operation one axis at a time gives us a MASSIVE performance boost + * at large morphology radii. Extreme of row extremes is equal to the extreme + * of components, so this doesn't change the result. */ +template <MorphologyOp OP, Geom::Dim2 axis> +struct Morphology : public SurfaceSynth { + Morphology(cairo_surface_t *in, double xradius) + : SurfaceSynth(in) + , _radius(round(xradius)) + {} + guint32 operator()(int x, int y) { + int start, end; + if (axis == Geom::X) { + start = std::max(0, x - _radius); + end = std::min(x + _radius + 1, _w); + } else { + start = std::max(0, y - _radius); + end = std::min(y + _radius + 1, _h); + } - Geom::Affine p2pb = units.get_matrix_primitiveunits2pb(); - int const xradius = (int)round(this->xradius * p2pb.expansionX()); - int const yradius = (int)round(this->yradius * p2pb.expansionY()); - - int x0=in->area.x0; - int y0=in->area.y0; - int x1=in->area.x1; - int y1=in->area.y1; - int w=x1-x0, h=y1-y0; - int x, y, i, j; - int rmax,gmax,bmax,amax; - int rmin,gmin,bmin,amin; - - nr_pixblock_setup_fast(out, in->mode, x0, y0, x1, y1, true); - - unsigned char *in_data = NR_PIXBLOCK_PX(in); - unsigned char *out_data = NR_PIXBLOCK_PX(out); - - for(x = 0 ; x < w ; x++){ - for(y = 0 ; y < h ; y++){ - rmin = gmin = bmin = amin = 255; - rmax = gmax = bmax = amax = 0; - for(i = x - xradius ; i < x + xradius ; i++){ - if (i < 0 || i >= w) continue; - for(j = y - yradius ; j < y + yradius ; j++){ - if (j < 0 || j >= h) continue; - if(in_data[4*(i + w*j)]>rmax) rmax = in_data[4*(i + w*j)]; - if(in_data[4*(i + w*j)+1]>gmax) gmax = in_data[4*(i + w*j)+1]; - if(in_data[4*(i + w*j)+2]>bmax) bmax = in_data[4*(i + w*j)+2]; - if(in_data[4*(i + w*j)+3]>amax) amax = in_data[4*(i + w*j)+3]; - - if(in_data[4*(i + w*j)]<rmin) rmin = in_data[4*(i + w*j)]; - if(in_data[4*(i + w*j)+1]<gmin) gmin = in_data[4*(i + w*j)+1]; - if(in_data[4*(i + w*j)+2]<bmin) bmin = in_data[4*(i + w*j)+2]; - if(in_data[4*(i + w*j)+3]<amin) amin = in_data[4*(i + w*j)+3]; + guint32 ao = (OP == DILATE ? 0 : 255); + guint32 ro = (OP == DILATE ? 0 : 255); + guint32 go = (OP == DILATE ? 0 : 255); + guint32 bo = (OP == DILATE ? 0 : 255); + + if (_alpha) { + ao = (OP == DILATE ? 0 : 0xff000000); + for (int i = start; i < end; ++i) { + guint32 px = (axis == Geom::X ? pixelAt(i, y) : pixelAt(x, i)); + if (OP == DILATE) { + if (px > ao) ao = px; + } else { + if (px < ao) ao = px; } } - if (Operator==MORPHOLOGY_OPERATOR_DILATE){ - out_data[4*(x + w*y)]=rmax; - out_data[4*(x + w*y)+1]=gmax; - out_data[4*(x + w*y)+2]=bmax; - out_data[4*(x + w*y)+3]=amax; - } else { - out_data[4*(x + w*y)]=rmin; - out_data[4*(x + w*y)+1]=gmin; - out_data[4*(x + w*y)+2]=bmin; - out_data[4*(x + w*y)+3]=amin; + return ao; + } else { + for (int i = start; i < end; ++i) { + guint32 px = (axis == Geom::X ? pixelAt(i, y) : pixelAt(x, i)); + EXTRACT_ARGB32(px, a,r,g,b); + + // this will be compiled to conditional moves; + // the operator comparison will be evaluated at compile time. + // therefore there will be no branching in this loop + if (OP == DILATE) { + if (a > ao) ao = a; + if (r > ro) ro = r; + if (g > go) go = g; + if (b > bo) bo = b; + } else { + if (a < ao) ao = a; + if (r < ro) ro = r; + if (g < go) go = g; + if (b < bo) bo = b; + } + + // TODO: verify whether this check gives any speedup. + if (OP == ERODE && a == 0) break; } + + ASSEMBLE_ARGB32(pxout, ao,ro,go,bo) + return pxout; } } +private: + int _radius; +}; + +} // end anonymous namespace - if (free_in_on_exit) { - nr_pixblock_release(in); - delete in; +void FilterMorphology::render_cairo(FilterSlot &slot) +{ + cairo_surface_t *input = slot.getcairo(_input); + + if (xradius == 0.0 || yradius == 0.0) { + // output is transparent black + cairo_surface_t *out = ink_cairo_surface_create_identical(input); + slot.set(_output, out); + cairo_surface_destroy(out); + return; } - out->empty = FALSE; + Geom::Affine p2pb = slot.get_units().get_matrix_primitiveunits2pb(); + double xr = xradius * p2pb.expansionX(); + double yr = yradius * p2pb.expansionY(); + + cairo_surface_t *interm = ink_cairo_surface_create_identical(input); + + if (Operator == MORPHOLOGY_OPERATOR_DILATE) { + ink_cairo_surface_synthesize(interm, Morphology<DILATE, Geom::X>(input, xr)); + } else { + ink_cairo_surface_synthesize(interm, Morphology<ERODE, Geom::X>(input, xr)); + } + + cairo_surface_t *out = ink_cairo_surface_create_identical(input); + + if (Operator == MORPHOLOGY_OPERATOR_DILATE) { + ink_cairo_surface_synthesize(out, Morphology<DILATE, Geom::Y>(interm, yr)); + } else { + ink_cairo_surface_synthesize(out, Morphology<ERODE, Geom::Y>(interm, yr)); + } + + cairo_surface_destroy(interm); + slot.set(_output, out); - return 0; + cairo_surface_destroy(out); } void FilterMorphology::area_enlarge(NRRectL &area, Geom::Affine const &trans) { - int const enlarge_x = (int)std::ceil(this->xradius * (std::fabs(trans[0]) + std::fabs(trans[1]))); - int const enlarge_y = (int)std::ceil(this->yradius * (std::fabs(trans[2]) + std::fabs(trans[3]))); + int enlarge_x = ceil(xradius * trans.expansionX()); + int enlarge_y = ceil(yradius * trans.expansionY()); area.x0 -= enlarge_x; area.x1 += enlarge_x; @@ -135,10 +170,6 @@ void FilterMorphology::set_yradius(double y){ yradius = y; } -FilterTraits FilterMorphology::get_input_traits() { - return TRAIT_PARALLER; -} - } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-morphology.h b/src/display/nr-filter-morphology.h index c8d8b2f50..5924085d9 100644 --- a/src/display/nr-filter-morphology.h +++ b/src/display/nr-filter-morphology.h @@ -13,12 +13,12 @@ */ #include "display/nr-filter-primitive.h" -#include "display/nr-filter-slot.h" -#include "display/nr-filter-units.h" namespace Inkscape { namespace Filters { +class FilterSlot; + enum FilterMorphologyOperator { MORPHOLOGY_OPERATOR_ERODE, MORPHOLOGY_OPERATOR_DILATE, @@ -31,9 +31,8 @@ public: static FilterPrimitive *create(); virtual ~FilterMorphology(); - virtual int render(FilterSlot &slot, FilterUnits const &units); + virtual void render_cairo(FilterSlot &slot); virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); - virtual FilterTraits get_input_traits(); void set_operator(FilterMorphologyOperator &o); void set_xradius(double x); void set_yradius(double y); diff --git a/src/display/nr-filter-offset.cpp b/src/display/nr-filter-offset.cpp index 7c924b7b7..3b0f83841 100644 --- a/src/display/nr-filter-offset.cpp +++ b/src/display/nr-filter-offset.cpp @@ -9,11 +9,10 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include "display/cairo-utils.h" #include "display/nr-filter-offset.h" #include "display/nr-filter-slot.h" #include "display/nr-filter-units.h" -#include "libnr/nr-blit.h" -#include "libnr/nr-pixblock.h" #include "libnr/nr-rect-l.h" namespace Inkscape { @@ -33,37 +32,29 @@ FilterPrimitive * FilterOffset::create() { FilterOffset::~FilterOffset() {} -int FilterOffset::render(FilterSlot &slot, FilterUnits const &units) { - NRPixBlock *in = slot.get(_input); - // Bail out if source image is missing - if (!in) { - g_warning("Missing source image for feOffset (in=%d)", _input); - return 1; - } - - NRPixBlock *out = new NRPixBlock; +void FilterOffset::render_cairo(FilterSlot &slot) +{ + cairo_surface_t *in = slot.getcairo(_input); + cairo_surface_t *out = ink_cairo_surface_create_identical(in); + cairo_t *ct = cairo_create(out); - Geom::Affine trans = units.get_matrix_primitiveunits2pb(); + Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); Geom::Point offset(dx, dy); offset *= trans; offset[X] -= trans[4]; offset[Y] -= trans[5]; - nr_pixblock_setup_fast(out, in->mode, - in->area.x0, in->area.y0, in->area.x1, in->area.y1, - true); - nr_blit_pixblock_pixblock(out, in); + cairo_set_source_surface(ct, in, offset[X], offset[Y]); + cairo_paint(ct); + cairo_destroy(ct); - out->area.x0 += static_cast<NR::ICoord>(offset[X]); - out->area.y0 += static_cast<NR::ICoord>(offset[Y]); - out->area.x1 += static_cast<NR::ICoord>(offset[X]); - out->area.y1 += static_cast<NR::ICoord>(offset[Y]); - out->visible_area = out->area; - - out->empty = FALSE; slot.set(_output, out); + cairo_surface_destroy(out); +} - return 0; +bool FilterOffset::can_handle_affine(Geom::Affine const &) +{ + return true; } void FilterOffset::set_dx(double amount) { @@ -82,15 +73,15 @@ void FilterOffset::area_enlarge(NRRectL &area, Geom::Affine const &trans) offset[Y] -= trans[5]; if (offset[X] > 0) { - area.x0 -= static_cast<NR::ICoord>(offset[X]); + area.x0 -= ceil(offset[X]); } else { - area.x1 -= static_cast<NR::ICoord>(offset[X]); + area.x1 -= floor(offset[X]); } if (offset[Y] > 0) { - area.y0 -= static_cast<NR::ICoord>(offset[Y]); + area.y0 -= ceil(offset[Y]); } else { - area.y1 -= static_cast<NR::ICoord>(offset[Y]); + area.y1 -= floor(offset[Y]); } } diff --git a/src/display/nr-filter-offset.h b/src/display/nr-filter-offset.h index a78450e17..09c57f803 100644 --- a/src/display/nr-filter-offset.h +++ b/src/display/nr-filter-offset.h @@ -26,8 +26,9 @@ public: static FilterPrimitive *create(); virtual ~FilterOffset(); - virtual int render(FilterSlot &slot, FilterUnits const &units); + virtual void render_cairo(FilterSlot &slot); virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); + virtual bool can_handle_affine(Geom::Affine const &); void set_dx(double amount); void set_dy(double amount); diff --git a/src/display/nr-filter-pixops.h b/src/display/nr-filter-pixops.h deleted file mode 100644 index afd9e98bd..000000000 --- a/src/display/nr-filter-pixops.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef __NR_FILTER_PIXOPS_H__ -#define __NR_FILTER_PIXOPS_H__ - -#include "libnr/nr-pixblock.h" -#include <algorithm> - -/* - * Per-pixel image manipulation functions. - * These can be used by all filter primitives, which combine two images on - * per-pixel basis. These are at least feBlend, feComposite and feMerge. - * - * Authors: - * Niko Kiirala <niko@kiirala.com> - * - * Copyright (C) 2007 authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -namespace Inkscape { -namespace Filters { - -/** - * Mixes the two input images using the function given as template. - * The result is placed in out. - * The mixing function should have the following type: - * void mix(unsigned char *result, unsigned char const *in1, - * unsigned char const *in2); - * Each of the parameters for mix-function is a pointer to four bytes of data, - * giving the RGBA values for that pixel. The mix function must only access - * the four bytes beginning at a pointer given as parameter. - */ -/* - * The implementation is in a header file because of the template. It has to - * be in the same compilation unit as the code using it. Otherwise, linking - * the program will not succeed. - */ -template <void(*blend)(unsigned char *cr, unsigned char const *ca, unsigned char const *cb)> -void pixops_mix(NRPixBlock &out, NRPixBlock &in1, NRPixBlock &in2) { - unsigned char *in1_data = NR_PIXBLOCK_PX(&in1); - unsigned char *in2_data = NR_PIXBLOCK_PX(&in2); - unsigned char *out_data = NR_PIXBLOCK_PX(&out); - unsigned char zero_rgba[4] = {0, 0, 0, 0}; - - // Possible scenarios (omitting cases where an interval is empty and those which are the same by interchanging 1 and 2): - // 01020, 01320, 01310 (no overlap, partial overlap, full overlap) - int out_y0 = out.area.y0; - int out_y1 = std::max(out.area.y1,out_y0); // Enforce sanity - int in1_y0 = std::min(std::max(in1.area.y0,out_y0),out_y1); - int in2_y0 = std::min(std::max(in2.area.y0,out_y0),out_y1); - int in1_y1 = std::min(std::max(in1.area.y1,in1_y0),out_y1); - int in2_y1 = std::min(std::max(in2.area.y1,in2_y0),out_y1); - int min_in_y0 = std::min(in1_y0,in2_y0); - int max_in_y0 = std::max(in1_y0,in2_y0); - int min_in_y1 = std::min(in1_y1,in2_y1); - int max_in_y1 = std::max(in1_y1,in2_y1); - int const yBound[6] = {out_y0, min_in_y0, std::min(max_in_y0,min_in_y1), std::max(max_in_y0,min_in_y1), max_in_y1, out_y1}; - bool const in1_zero_y[5] = {true, in1_y0>yBound[1], in1_y0>yBound[2] || in1_y1<=yBound[2], in1_y1<=yBound[3], true}; - bool const in2_zero_y[5] = {true, in2_y0>yBound[1], in2_y0>yBound[2] || in2_y1<=yBound[2], in2_y1<=yBound[3], true}; - - int out_x0 = out.area.x0; - int out_x1 = std::max(out.area.x1,out_x0); - int in1_x0 = std::min(std::max(in1.area.x0,out_x0),out_x1); - int in2_x0 = std::min(std::max(in2.area.x0,out_x0),out_x1); - int in1_x1 = std::min(std::max(in1.area.x1,in1_x0),out_x1); - int in2_x1 = std::min(std::max(in2.area.x1,in2_x0),out_x1); - int min_in_x0 = std::min(in1_x0,in2_x0); - int max_in_x0 = std::max(in1_x0,in2_x0); - int min_in_x1 = std::min(in1_x1,in2_x1); - int max_in_x1 = std::max(in1_x1,in2_x1); - int const xBound[6] = {out_x0, min_in_x0, std::min(max_in_x0,min_in_x1), std::max(max_in_x0,min_in_x1), max_in_x1, out_x1}; - bool const in1_zero_x[5] = {true, in1_x0>xBound[1], in1_x0>xBound[2] || in1_x1<=xBound[2], in1_x1<=xBound[3], true}; - bool const in2_zero_x[5] = {true, in2_x0>xBound[1], in2_x0>xBound[2] || in2_x1<=xBound[2], in2_x1<=xBound[3], true}; - - for (int yr = 0 ; yr < 5 ; yr++) { - for(int y = yBound[yr] ; y < yBound[yr+1] ; y++) { - int out_line = (y - out.area.y0) * out.rs; - int in1_line = (y - in1.area.y0) * in1.rs; - int in2_line = (y - in2.area.y0) * in2.rs; - for (int xr = 0 ; xr < 5 ; xr++) { - for(int x = xBound[xr] ; x < xBound[xr+1] ; x++) { - blend(out_data + out_line + 4 * (x - out.area.x0), - (in1_zero_x[xr]||in1_zero_y[yr]) ? zero_rgba : (in1_data + in1_line + 4 * (x - in1.area.x0)), - (in2_zero_x[xr]||in2_zero_y[yr]) ? zero_rgba : (in2_data + in2_line + 4 * (x - in2.area.x0))); - } - } - } - } -} - -} /* namespace Filters */ -} /* namespace Inkscape */ - -#endif // __NR_FILTER_PIXOPS_H_ -/* - 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 : diff --git a/src/display/nr-filter-primitive.cpp b/src/display/nr-filter-primitive.cpp index 1af86ec3e..b544d6df0 100644 --- a/src/display/nr-filter-primitive.cpp +++ b/src/display/nr-filter-primitive.cpp @@ -13,8 +13,8 @@ */ #include "display/nr-filter-primitive.h" +#include "display/nr-filter-slot.h" #include "display/nr-filter-types.h" -#include "libnr/nr-pixblock.h" #include "svg/svg-length.h" namespace Inkscape { @@ -48,6 +48,13 @@ FilterPrimitive::~FilterPrimitive() // Nothing to do here } +void FilterPrimitive::render_cairo(FilterSlot &slot) +{ + // passthrough + cairo_surface_t *in = slot.getcairo(_input); + slot.set(_output, in); +} + void FilterPrimitive::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*m*/) { // This doesn't need to do anything by default diff --git a/src/display/nr-filter-primitive.h b/src/display/nr-filter-primitive.h index 0e8df3813..dd7363d76 100644 --- a/src/display/nr-filter-primitive.h +++ b/src/display/nr-filter-primitive.h @@ -1,6 +1,3 @@ -#ifndef __NR_FILTER_PRIMITIVE_H__ -#define __NR_FILTER_PRIMITIVE_H__ - /* * SVG filters rendering * @@ -11,15 +8,20 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifndef SEEN_NR_FILTER_PRIMITIVE_H +#define SEEN_NR_FILTER_PRIMITIVE_H -#include "display/nr-filter-slot.h" -#include "libnr/nr-pixblock.h" -#include "libnr/nr-rect-l.h" +#include <2geom/forward.h> #include "svg/svg-length.h" +struct NRRectL; + namespace Inkscape { namespace Filters { +class FilterSlot; +class FilterUnits; + /* * Different filter effects need different types of inputs. This is what * traits are used for: one can specify, what special restrictions @@ -43,7 +45,8 @@ public: FilterPrimitive(); virtual ~FilterPrimitive(); - virtual int render(FilterSlot &slot, FilterUnits const &units) = 0; + virtual void render_cairo(FilterSlot &slot); + virtual int render(FilterSlot &slot, FilterUnits const &units) { return 0; } virtual void area_enlarge(NRRectL &area, Geom::Affine const &m); /** @@ -108,6 +111,20 @@ public: */ virtual FilterTraits get_input_traits(); + /** @brief Indicate whether the filter primitive can handle the given affine. + * + * Results of some filter primitives depend on the coordinate system used when rendering. + * A gaussian blur with equal x and y deviation will remain unchanged by rotations. + * Per-pixel filters like color matrix and blend will not change regardless of + * the transformation. + * + * When any filter returns false, filter rendering is performed on an intermediate surface + * with edges parallel to the axes of the user coordinate system. This means + * the matrices from FilterUnits will contain at most a (possibly non-uniform) scale + * and a translation. When all primitives of the filter return false, the rendering is + * performed in display coordinate space and no intermediate surface is used. */ + virtual bool can_handle_affine(Geom::Affine const &) { return false; } + protected: int _input; int _output; diff --git a/src/display/nr-filter-skeleton.cpp b/src/display/nr-filter-skeleton.cpp index c17bee1d4..0c455a818 100644 --- a/src/display/nr-filter-skeleton.cpp +++ b/src/display/nr-filter-skeleton.cpp @@ -22,9 +22,9 @@ */ #include "display/nr-filter-skeleton.h" +#include "display/cairo-utils.h" #include "display/nr-filter-slot.h" #include "display/nr-filter-units.h" -#include "libnr/nr-pixblock.h" namespace Inkscape { namespace Filters { @@ -39,17 +39,17 @@ FilterPrimitive * FilterSkeleton::create() { FilterSkeleton::~FilterSkeleton() {} -int FilterSkeleton::render(FilterSlot &slot, - FilterUnits const &/*units*/) { - //NRPixBlock *in = slot.get(_input); - NRPixBlock *out = new NRPixBlock(); +void FilterSkeleton::render_cairo(FilterSlot &slot) { + cairo_surface_t *in = slot.getcairo(_input); + cairo_surface_t *out = ink_cairo_surface_create_identical(in); + cairo_t *ct = cairo_create(out); - /* Insert rendering code here */ +// cairo_set_source_surface(ct, in, offset[X], offset[Y]); +// cairo_paint(ct); +// cairo_destroy(ct); - out->empty = FALSE; slot.set(_output, out); - - return 0; + cairo_surface_destroy(out); } } /* namespace Filters */ diff --git a/src/display/nr-filter-skeleton.h b/src/display/nr-filter-skeleton.h index a03004be1..049c0df80 100644 --- a/src/display/nr-filter-skeleton.h +++ b/src/display/nr-filter-skeleton.h @@ -37,7 +37,7 @@ public: static FilterPrimitive *create(); virtual ~FilterSkeleton(); - virtual int render(FilterSlot &slot, FilterUnits const &units); + virtual void render_cairo(FilterSlot &slot); private: diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index b019b194f..ce07ff086 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -14,317 +14,219 @@ #include <assert.h> #include <string.h> +#include <2geom/transforms.h> +#include "display/cairo-utils.h" #include "display/nr-arena-item.h" #include "display/nr-filter-types.h" #include "display/nr-filter-gaussian.h" #include "display/nr-filter-slot.h" -#include "display/nr-filter-getalpha.h" #include "display/nr-filter-units.h" -#include "display/pixblock-scaler.h" -#include "display/pixblock-transform.h" -#include "libnr/nr-pixblock.h" -#include "libnr/nr-blit.h" - -__attribute__ ((const)) -inline static int _max4(const double a, const double b, - const double c, const double d) { - double ret = a; - if (b > ret) ret = b; - if (c > ret) ret = c; - if (d > ret) ret = d; - return (int)round(ret); -} - -__attribute__ ((const)) -inline static int _min4(const double a, const double b, - const double c, const double d) { - double ret = a; - if (b < ret) ret = b; - if (c < ret) ret = c; - if (d < ret) ret = d; - return (int)round(ret); -} - -__attribute__ ((const)) -inline static int _max2(const double a, const double b) { - if (a > b) - return (int)round(a); - else - return (int)round(b); -} - -__attribute__ ((const)) -inline static int _min2(const double a, const double b) { - if (a > b) - return (int)round(b); - else - return (int)round(a); -} namespace Inkscape { namespace Filters { -FilterSlot::FilterSlot(int slots, NRArenaItem const *item) - : _last_out(-1), - filterquality(FILTER_QUALITY_BEST), - blurquality(BLUR_QUALITY_BEST), - _arena_item(item) +FilterSlot::FilterSlot(NRArenaItem *item, cairo_t *bgct, NRRectL const *bgarea, + cairo_surface_t *graphic, NRRectL const *graphicarea, FilterUnits const &u) + : _item(item) + , _source_graphic(graphic) + , _background_ct(bgct) + , _source_graphic_area(graphicarea) + , _background_area(bgarea) + , _units(u) + , _last_out(NR_FILTER_SOURCEGRAPHIC) + , filterquality(FILTER_QUALITY_BEST) + , blurquality(BLUR_QUALITY_BEST) { - _slots.reserve((slots > 0) ? slots : 2); + using Geom::X; + using Geom::Y; + + // compute slot bbox + Geom::Rect bbox( + Geom::Point(_source_graphic_area->x0, _source_graphic_area->y0), + Geom::Point(_source_graphic_area->x1, _source_graphic_area->y1)); + + Geom::Affine trans = _units.get_matrix_display2pb(); + Geom::Rect bbox_trans = bbox * trans; + Geom::Point min = bbox_trans.min(); + _slot_x = min[X]; + _slot_y = min[Y]; + + if (trans.isTranslation()) { + _slot_w = _source_graphic_area->x1 - _source_graphic_area->x0; + _slot_h = _source_graphic_area->y1 - _source_graphic_area->y0; + } else { + _slot_w = ceil(bbox_trans.width()); + _slot_h = ceil(bbox_trans.height()); + } } FilterSlot::~FilterSlot() { - for (unsigned int i = 0 ; i < _slots.size() ; i++) { - if (_slots[i].owned) { - nr_pixblock_release(_slots[i].pb); - delete _slots[i].pb; - } + for (SlotMap::iterator i = _slots.begin(); i != _slots.end(); ++i) { + cairo_surface_destroy(i->second); } } -FilterSlot::slot_entry_t::~slot_entry_t() +cairo_surface_t *FilterSlot::getcairo(int slot_nr) { - // It's a bad idea to destruct pixblocks here, as this will also be called upon resizing _slots -} + if (slot_nr == NR_FILTER_SLOT_NOT_SET) + slot_nr = _last_out; -NRPixBlock *FilterSlot::get(int slot_nr) -{ - int index = _get_index(slot_nr); - assert(index >= 0); + 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 (_slots[index].pb == NULL - && (slot_nr == NR_FILTER_SOURCEALPHA + 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)) { - /* If needed, fetch background */ - if (slot_nr == NR_FILTER_BACKGROUNDIMAGE) { - NRPixBlock *pb; - pb = nr_arena_item_get_background(_arena_item); - if (pb) { - pb->empty = false; - this->set(NR_FILTER_BACKGROUNDIMAGE, pb, false); - } else { - NRPixBlock *source = this->get(NR_FILTER_SOURCEGRAPHIC); - pb = new NRPixBlock(); - if (!pb) return NULL; // Allocation failed - nr_pixblock_setup_fast(pb, source->mode, - source->area.x0, source->area.y0, - source->area.x1, source->area.y1, true); - if (pb->size != NR_PIXBLOCK_SIZE_TINY && pb->data.px == NULL) { - // allocation failed - delete pb; - return NULL; - } - pb->empty = FALSE; - this->set(NR_FILTER_BACKGROUNDIMAGE, pb); - } - } else if (slot_nr == NR_FILTER_SOURCEALPHA) { - /* If only a alpha channel is needed, strip it from full image */ - NRPixBlock *src = get(NR_FILTER_SOURCEGRAPHIC); - NRPixBlock *sa = filter_get_alpha(src); - set(NR_FILTER_SOURCEALPHA, sa); - } else if (slot_nr == NR_FILTER_BACKGROUNDALPHA) { - NRPixBlock *src = get(NR_FILTER_BACKGROUNDIMAGE); - NRPixBlock *ba = filter_get_alpha(src); - set(NR_FILTER_BACKGROUNDALPHA, ba); - } else if (slot_nr == NR_FILTER_FILLPAINT) { - /* When a paint is needed, fetch it from arena item */ - // TODO - } else if (slot_nr == NR_FILTER_STROKEPAINT) { - // TODO + switch (slot_nr) { + case NR_FILTER_SOURCEGRAPHIC: { + cairo_surface_t *tr = _get_transformed_source_graphic(); + _set_internal(NR_FILTER_SOURCEGRAPHIC, tr); + cairo_surface_destroy(tr); + } break; + case NR_FILTER_BACKGROUNDIMAGE: { + cairo_surface_t *bg = _get_transformed_background(); + _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 (_slots[index].pb) { - _slots[index].pb->empty = false; + 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); } - - assert(slot_nr == NR_FILTER_SLOT_NOT_SET ||_slots[index].number == slot_nr); - return _slots[index].pb; + return s->second; } -void FilterSlot::get_final(int slot_nr, NRPixBlock *result) { - NRPixBlock *final_usr = get(slot_nr); - Geom::Affine trans = units.get_matrix_pb2display(); - - int size = (result->area.x1 - result->area.x0) - * (result->area.y1 - result->area.y0) - * NR_PIXBLOCK_BPP(result); - memset(NR_PIXBLOCK_PX(result), 0, size); +cairo_surface_t *FilterSlot::_get_transformed_source_graphic() +{ + Geom::Affine trans = _units.get_matrix_display2pb(); - if (fabs(trans[1]) > 1e-6 || fabs(trans[2]) > 1e-6) { - if (filterquality == FILTER_QUALITY_BEST) { - NR::transform_bicubic(result, final_usr, trans); - } else { - NR::transform_nearest(result, final_usr, trans); - } - } else if (fabs(trans[0] - 1) > 1e-6 || fabs(trans[3] - 1) > 1e-6) { - NR::scale_bicubic(result, final_usr, trans); - } else { - nr_blit_pixblock_pixblock(result, final_usr); + if (trans.isTranslation()) { + cairo_surface_reference(_source_graphic); + return _source_graphic; } -} -void FilterSlot::set(int slot_nr, NRPixBlock *pb, bool takeOwnership) -{ - /* Unnamed slot is for saving filter primitive results, when parameter - * 'result' is not set. Only the filter immediately after this one - * can access unnamed results, so we don't have to worry about overwriting - * previous results in filter chain. On the other hand, we may not - * overwrite any other image with this one, because they might be - * accessed later on. */ - int index = ((slot_nr != NR_FILTER_SLOT_NOT_SET) - ? _get_index(slot_nr) - : _get_index(NR_FILTER_UNNAMED_SLOT)); - assert(index >= 0); - // Unnamed slot is only for Inkscape::Filters::FilterSlot internal use. - assert(slot_nr != NR_FILTER_UNNAMED_SLOT); - assert(slot_nr == NR_FILTER_SLOT_NOT_SET ||_slots[index].number == slot_nr); - - if (slot_nr == NR_FILTER_SOURCEGRAPHIC || slot_nr == NR_FILTER_BACKGROUNDIMAGE) { - Geom::Affine trans = units.get_matrix_display2pb(); - if (fabs(trans[1]) > 1e-6 || fabs(trans[2]) > 1e-6) { - NRPixBlock *trans_pb = new NRPixBlock; - int x0 = pb->area.x0; - int y0 = pb->area.y0; - int x1 = pb->area.x1; - int y1 = pb->area.y1; - int min_x = _min4(trans[0] * x0 + trans[2] * y0 + trans[4], - trans[0] * x0 + trans[2] * y1 + trans[4], - trans[0] * x1 + trans[2] * y0 + trans[4], - trans[0] * x1 + trans[2] * y1 + trans[4]); - int max_x = _max4(trans[0] * x0 + trans[2] * y0 + trans[4], - trans[0] * x0 + trans[2] * y1 + trans[4], - trans[0] * x1 + trans[2] * y0 + trans[4], - trans[0] * x1 + trans[2] * y1 + trans[4]); - int min_y = _min4(trans[1] * x0 + trans[3] * y0 + trans[5], - trans[1] * x0 + trans[3] * y1 + trans[5], - trans[1] * x1 + trans[3] * y0 + trans[5], - trans[1] * x1 + trans[3] * y1 + trans[5]); - int max_y = _max4(trans[1] * x0 + trans[3] * y0 + trans[5], - trans[1] * x0 + trans[3] * y1 + trans[5], - trans[1] * x1 + trans[3] * y0 + trans[5], - trans[1] * x1 + trans[3] * y1 + trans[5]); - - nr_pixblock_setup_fast(trans_pb, pb->mode, - min_x, min_y, - max_x, max_y, true); - if (trans_pb->size != NR_PIXBLOCK_SIZE_TINY && trans_pb->data.px == NULL) { - /* TODO: this gets hit occasionally. Worst case scenario: - * images are exported in horizontal stripes. One stripe - * is not too high, but can get thousands of pixels wide. - * Rotate this 45 degrees -> _huge_ image */ - g_warning("Memory allocation failed in Inkscape::Filters::FilterSlot::set (transform)"); - if (takeOwnership) { - nr_pixblock_release(pb); - delete pb; - } - return; - } - if (filterquality == FILTER_QUALITY_BEST) { - NR::transform_bicubic(trans_pb, pb, trans); - } else { - NR::transform_nearest(trans_pb, pb, trans); - } - if (takeOwnership) { - nr_pixblock_release(pb); - delete pb; - } - takeOwnership = true; - pb = trans_pb; - } else if (fabs(trans[0] - 1) > 1e-6 || fabs(trans[3] - 1) > 1e-6) { - NRPixBlock *trans_pb = new NRPixBlock; - - int x0 = pb->area.x0; - int y0 = pb->area.y0; - int x1 = pb->area.x1; - int y1 = pb->area.y1; - int min_x = _min2(trans[0] * x0 + trans[4], - trans[0] * x1 + trans[4]); - int max_x = _max2(trans[0] * x0 + trans[4], - trans[0] * x1 + trans[4]); - int min_y = _min2(trans[3] * y0 + trans[5], - trans[3] * y1 + trans[5]); - int max_y = _max2(trans[3] * y0 + trans[5], - trans[3] * y1 + trans[5]); - - nr_pixblock_setup_fast(trans_pb, pb->mode, - min_x, min_y, max_x, max_y, true); - if (trans_pb->size != NR_PIXBLOCK_SIZE_TINY && trans_pb->data.px == NULL) { - g_warning("Memory allocation failed in Inkscape::Filters::FilterSlot::set (scaling)"); - if (takeOwnership) { - nr_pixblock_release(pb); - delete pb; - } - return; - } - NR::scale_bicubic(trans_pb, pb, trans); - if (takeOwnership) { - nr_pixblock_release(pb); - delete pb; - } - takeOwnership = true; - pb = trans_pb; - } - } + 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); - if(_slots[index].owned) { - nr_pixblock_release(_slots[index].pb); - delete _slots[index].pb; - } - _slots[index].pb = pb; - _slots[index].owned = takeOwnership; - _last_out = index; + cairo_translate(tsg_ct, -_slot_x, -_slot_y); + ink_cairo_transform(tsg_ct, trans); + cairo_translate(tsg_ct, _source_graphic_area->x0, _source_graphic_area->y0); + 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; } -int FilterSlot::get_slot_count() +cairo_surface_t *FilterSlot::_get_transformed_background() { - return _slots.size(); + Geom::Affine trans = _units.get_matrix_display2pb(); + + cairo_surface_t *bg = cairo_get_target(_background_ct); + cairo_surface_t *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->x0, _background_area->y0); + 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); + + return tbg; } -NRArenaItem const* FilterSlot::get_arenaitem() +cairo_surface_t *FilterSlot::get_result(int res) { - return _arena_item; + Geom::Affine trans = _units.get_matrix_pb2display(); + if (trans.isIdentity()) { + cairo_surface_t *result = getcairo(res); + 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->x1 - _source_graphic_area->x0, + _source_graphic_area->y1 - _source_graphic_area->y0); + cairo_t *r_ct = cairo_create(r); + + cairo_translate(r_ct, -_source_graphic_area->x0, -_source_graphic_area->y0); + ink_cairo_transform(r_ct, trans); + cairo_translate(r_ct, _slot_x, _slot_y); + cairo_set_source_surface(r_ct, getcairo(res), 0, 0); + cairo_set_operator(r_ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(r_ct); + cairo_destroy(r_ct); + + return r; } -int FilterSlot::_get_index(int slot_nr) +void FilterSlot::_set_internal(int slot_nr, cairo_surface_t *surface) { - assert(slot_nr >= 0 || - slot_nr == NR_FILTER_SLOT_NOT_SET || - 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 || - slot_nr == NR_FILTER_UNNAMED_SLOT); - - if (slot_nr == NR_FILTER_SLOT_NOT_SET) { - return _last_out; - } + // destroy after referencing + // this way assigning a surface to a slot it already occupies will not cause errors + cairo_surface_reference(surface); - /* Search, if the slot already exists */ - for (int i = 0 ; i < (int)_slots.size() ; i++) { - if (_slots[i].number == slot_nr) { - return i; - } + SlotMap::iterator s = _slots.find(slot_nr); + if (s != _slots.end()) { + cairo_surface_destroy(s->second); } - /* If the slot doesn't already exist, create it */ - slot_entry_t entry; - entry.number = slot_nr; - _slots.push_back(entry); - return (int)_slots.size()-1; + _slots[slot_nr] = surface; } -void FilterSlot::set_units(FilterUnits const &units) { - this->units = units; +void FilterSlot::set(int slot_nr, cairo_surface_t *surface) +{ + g_return_if_fail(surface != NULL); + + if (slot_nr == NR_FILTER_SLOT_NOT_SET) + slot_nr = NR_FILTER_UNNAMED_SLOT; + + _set_internal(slot_nr, surface); + _last_out = slot_nr; +} + +int FilterSlot::get_slot_count() +{ + return _slots.size(); } void FilterSlot::set_quality(FilterQuality const q) { @@ -339,6 +241,13 @@ int FilterSlot::get_blurquality(void) { return blurquality; } +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 */ diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h index 871d80a8e..3b08743ed 100644 --- a/src/display/nr-filter-slot.h +++ b/src/display/nr-filter-slot.h @@ -14,10 +14,10 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "libnr/nr-pixblock.h" +#include <map> +#include <cairo.h> #include "display/nr-filter-types.h" #include "display/nr-filter-units.h" -#include <vector> struct NRArenaItem; @@ -26,14 +26,9 @@ namespace Filters { class FilterSlot { public: - /** Creates a new FilterSlot object. - * First parameter specifies the amount of slots this SilterSlot - * should reserve beforehand. If a negative number is given, - * two slots will be reserved. - * Second parameter specifies the arena item, which should be used - * for background accesses from filters. - */ - FilterSlot(int slots, NRArenaItem const *item); + /** Creates a new FilterSlot object. */ + FilterSlot(NRArenaItem *item, cairo_t *bgct, NRRectL const *bgarea, + cairo_surface_t *graphic, NRRectL const *graphicarea, FilterUnits const &u); /** Destroys the FilterSlot object and all its contents */ virtual ~FilterSlot(); @@ -43,37 +38,22 @@ public: * 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); - - /** Gets the final result from this filter. - * The result is fetched from the specified slot, see description of - * method get for valid values. The pixblock 'result' will be modified - * to contain the result image, ready to be used in the rest of rendering - * pipeline */ - void get_final(int slot, NRPixBlock *result); + cairo_surface_t *getcairo(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 if takeOwnership==true. - * Pixblocks passed to this function should be reserved with - * c++ -style new-operator (if managed by FilterSlot). */ - void set(int slot, NRPixBlock *pb, bool takeOwnership=true); + void set(int slot, cairo_surface_t *s); + + cairo_surface_t *get_result(int slot_nr); /** Returns the number of slots in use. */ int get_slot_count(); - /** arenaitem getter method*/ - NRArenaItem const* get_arenaitem(); - /** Sets the unit system to be used for the internal images. */ - void set_units(FilterUnits const &units); + //void set_units(FilterUnits const &units); /** Sets the filtering quality. Affects used interpolation methods */ void set_quality(FilterQuality const q); @@ -84,30 +64,36 @@ public: /** Gets the gaussian filtering quality. Affects used interpolation methods */ int get_blurquality(void); -private: - struct slot_entry_t { - NRPixBlock* pb; - int number; - bool owned; - slot_entry_t() : pb(0), number(NR_FILTER_SLOT_NOT_SET), owned(false) {} - ~slot_entry_t(); - }; - std::vector<slot_entry_t> _slots; + FilterUnits const &get_units() const { return _units; } + Geom::Rect get_slot_area() const; + NRRectL const &get_sg_area() const { return *_source_graphic_area; } +private: + typedef std::map<int, cairo_surface_t *> SlotMap; + SlotMap _slots; + NRArenaItem *_item; + + //Geom::Rect _source_bbox; ///< bounding box of source graphic surface + //Geom::Rect _intermediate_bbox; ///< bounding box of intermediate surfaces + +// NRRectL _slot_area; + int _slot_w, _slot_h; + double _slot_x, _slot_y; + cairo_surface_t *_source_graphic; + cairo_t *_background_ct; + NRRectL const *_source_graphic_area; + NRRectL const *_background_area; ///< needed to extract background + FilterUnits const &_units; int _last_out; - FilterQuality filterquality; - int blurquality; - NRArenaItem const *_arena_item; - - FilterUnits units; + cairo_surface_t *_get_transformed_source_graphic(); + cairo_surface_t *_get_transformed_background(); + cairo_surface_t *_get_fill_paint(); + cairo_surface_t *_get_stroke_paint(); - /** Returns the table index of given slot. If that slot does not exist, - * it is created. Table index can be used to read the correct - * pixblock from _slot */ - int _get_index(int slot); + void _set_internal(int slot, cairo_surface_t *s); }; } /* namespace Filters */ diff --git a/src/display/nr-filter-specularlighting.cpp b/src/display/nr-filter-specularlighting.cpp index 8ecee24e6..eddab36a1 100644 --- a/src/display/nr-filter-specularlighting.cpp +++ b/src/display/nr-filter-specularlighting.cpp @@ -13,18 +13,15 @@ #include <glib/gmessages.h> #include <cmath> +#include "display/cairo-templates.h" +#include "display/cairo-utils.h" #include "display/nr-3dutils.h" -#include "display/nr-arena-item.h" #include "display/nr-filter-specularlighting.h" -#include "display/nr-filter-getalpha.h" #include "display/nr-filter-slot.h" #include "display/nr-filter-units.h" #include "display/nr-filter-utils.h" #include "display/nr-light.h" -#include "libnr/nr-blit.h" -#include "libnr/nr-pixblock.h" #include "libnr/nr-rect-l.h" -#include "color.h" namespace Inkscape { namespace Filters { @@ -45,20 +42,139 @@ FilterPrimitive * FilterSpecularLighting::create() { FilterSpecularLighting::~FilterSpecularLighting() {} -//Investigating Phong Lighting model we should not take N.H but -//R.E which equals to 2*N.H^2 - 1 -//replace the second line by -//gdouble scal = scalar_product((N), (H)); scal = 2 * scal * scal - 1; -//to get the expected formula -#define COMPUTE_INTER(inter, H, N, ks, speculaExponent) \ -do {\ - gdouble scal = NR::scalar_product((N), (H)); \ - if (scal <= 0)\ - (inter) = 0;\ - else\ - (inter) = (ks) * std::pow(scal, (specularExponent));\ -}while(0) +struct SpecularLight : public SurfaceSynth { + SpecularLight(cairo_surface_t *bumpmap, double scale, double specular_constant, + double specular_exponent) + : SurfaceSynth(bumpmap) + , _scale(scale) + , _ks(specular_constant) + , _exp(specular_exponent) + {} +protected: + guint32 specularLighting(int x, int y, NR::Fvector const &halfway, NR::Fvector const &light_components) { + NR::Fvector normal = surfaceNormalAt(x, y, _scale); + double sp = NR::scalar_product(normal, halfway); + double k = sp <= 0.0 ? 0.0 : _ks * pow(sp, _exp); + guint32 r = CLAMP_D_TO_U8(k * light_components[LIGHT_RED]); + guint32 g = CLAMP_D_TO_U8(k * light_components[LIGHT_GREEN]); + guint32 b = CLAMP_D_TO_U8(k * light_components[LIGHT_BLUE]); + guint32 a = std::max(std::max(r, g), b); + + r = premul_alpha(r, a); + g = premul_alpha(g, a); + b = premul_alpha(b, a); + + ASSEMBLE_ARGB32(pxout, a,r,g,b) + return pxout; + } + double _scale, _ks, _exp; +}; + +struct SpecularDistantLight : public SpecularLight { + SpecularDistantLight(cairo_surface_t *bumpmap, SPFeDistantLight *light, guint32 color, + double scale, double specular_constant, double specular_exponent) + : SpecularLight(bumpmap, scale, specular_constant, specular_exponent) + { + DistantLight dl(light, color); + NR::Fvector lv; + dl.light_vector(lv); + dl.light_components(_light_components); + NR::normalized_sum(_halfway, lv, NR::EYE_VECTOR); + } + guint32 operator()(int x, int y) { + return specularLighting(x, y, _halfway, _light_components); + } +private: + NR::Fvector _halfway, _light_components; +}; + +struct SpecularPointLight : public SpecularLight { + SpecularPointLight(cairo_surface_t *bumpmap, SPFePointLight *light, guint32 color, + Geom::Affine const &trans, double scale, double specular_constant, + double specular_exponent, double x0, double y0) + : SpecularLight(bumpmap, scale, specular_constant, specular_exponent) + , _light(light, color, trans) + , _x0(x0) + , _y0(y0) + { + _light.light_components(_light_components); + } + + guint32 operator()(int x, int y) { + NR::Fvector light, halfway; + _light.light_vector(light, _x0 + x, _y0 + y, _scale * alphaAt(x, y)/255.0); + NR::normalized_sum(halfway, light, NR::EYE_VECTOR); + return specularLighting(x, y, halfway, _light_components); + } +private: + PointLight _light; + NR::Fvector _light_components; + double _x0, _y0; +}; + +struct SpecularSpotLight : public SpecularLight { + SpecularSpotLight(cairo_surface_t *bumpmap, SPFeSpotLight *light, guint32 color, + Geom::Affine const &trans, double scale, double specular_constant, + double specular_exponent, double x0, double y0) + : SpecularLight(bumpmap, scale, specular_constant, specular_exponent) + , _light(light, color, trans) + , _x0(x0) + , _y0(y0) + {} + + guint32 operator()(int x, int y) { + NR::Fvector light, halfway, light_components; + _light.light_vector(light, _x0 + x, _y0 + y, _scale * alphaAt(x, y)/255.0); + _light.light_components(light_components, light); + NR::normalized_sum(halfway, light, NR::EYE_VECTOR); + return specularLighting(x, y, halfway, light_components); + } +private: + SpotLight _light; + double _x0, _y0; +}; + +void FilterSpecularLighting::render_cairo(FilterSlot &slot) +{ + cairo_surface_t *input = slot.getcairo(_input); + cairo_surface_t *out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_COLOR_ALPHA); + + Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); + Geom::Point p = slot.get_slot_area().min(); + double x0 = p[Geom::X]; + double y0 = p[Geom::Y]; + double scale = surfaceScale * trans.descrim(); + double ks = specularConstant; + double se = specularExponent; + + switch (light_type) { + case DISTANT_LIGHT: + ink_cairo_surface_synthesize(out, + SpecularDistantLight(input, light.distant, lighting_color, scale, ks, se)); + break; + case POINT_LIGHT: + ink_cairo_surface_synthesize(out, + SpecularPointLight(input, light.point, lighting_color, trans, scale, ks, se, x0, y0)); + break; + case SPOT_LIGHT: + ink_cairo_surface_synthesize(out, + SpecularSpotLight(input, light.spot, lighting_color, trans, scale, ks, se, x0, y0)); + break; + default: { + cairo_t *ct = cairo_create(out); + cairo_set_source_rgba(ct, 0,0,0,1); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); + cairo_destroy(ct); + } break; + } + + slot.set(_output, out); + cairo_surface_destroy(out); +} + +/* int FilterSpecularLighting::render(FilterSlot &slot, FilterUnits const &units) { NRPixBlock *in = slot.get(_input); if (!in) { @@ -186,23 +302,16 @@ int FilterSpecularLighting::render(FilterSlot &slot, FilterUnits const &units) { //nr_pixblock_release(in); //delete in; return 0; -} +}*/ void FilterSpecularLighting::area_enlarge(NRRectL &area, Geom::Affine const &trans) { // TODO: support kernelUnitLength - double scalex = std::fabs(trans[0]) + std::fabs(trans[1]); - double scaley = std::fabs(trans[2]) + std::fabs(trans[3]); - - //FIXME: no +2 should be there!... (noticable only for big scales at big zoom factor) - area.x0 -= (int)(scalex) + 2; - area.x1 += (int)(scalex) + 2; - area.y0 -= (int)(scaley) + 2; - area.y1 += (int)(scaley) + 2; -} -FilterTraits FilterSpecularLighting::get_input_traits() { - return TRAIT_PARALLER; + area.x0 -= 1; + area.x1 += 1; + area.y0 -= 1; + area.y1 += 1; } } /* namespace Filters */ diff --git a/src/display/nr-filter-specularlighting.h b/src/display/nr-filter-specularlighting.h index 7c278df89..2fcb02588 100644 --- a/src/display/nr-filter-specularlighting.h +++ b/src/display/nr-filter-specularlighting.h @@ -16,18 +16,24 @@ #include <gdk/gdk.h> #include "display/nr-light-types.h" #include "display/nr-filter-primitive.h" -#include "display/nr-filter-slot.h" -#include "display/nr-filter-units.h" -#include "filters/distantlight.h" -#include "filters/pointlight.h" -#include "filters/spotlight.h" -#include "color.h" + +class SPFeDistantLight; +class SPFePointLight; +class SPFeSpotLight; namespace Inkscape { namespace Filters { - + +class FilterSlot; + class FilterSpecularLighting : public FilterPrimitive { public: + FilterSpecularLighting(); + static FilterPrimitive *create(); + virtual ~FilterSpecularLighting(); + virtual void render_cairo(FilterSlot &slot); + virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); + union { SPFeDistantLight *distant; SPFePointLight *point; @@ -38,13 +44,6 @@ public: gdouble specularConstant; gdouble specularExponent; guint32 lighting_color; - - FilterSpecularLighting(); - static FilterPrimitive *create(); - virtual ~FilterSpecularLighting(); - virtual int render(FilterSlot &slot, FilterUnits const &units); - virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); - virtual FilterTraits get_input_traits(); private: }; diff --git a/src/display/nr-filter-tile.cpp b/src/display/nr-filter-tile.cpp index b1ca5d191..b88386638 100644 --- a/src/display/nr-filter-tile.cpp +++ b/src/display/nr-filter-tile.cpp @@ -10,6 +10,7 @@ */ #include "display/nr-filter-tile.h" +#include "display/nr-filter-slot.h" #include "display/nr-filter-units.h" namespace Inkscape { @@ -17,7 +18,6 @@ namespace Filters { FilterTile::FilterTile() { - g_warning("FilterTile::render not implemented."); } FilterPrimitive * FilterTile::create() { @@ -27,40 +27,24 @@ FilterPrimitive * FilterTile::create() { FilterTile::~FilterTile() {} -int FilterTile::render(FilterSlot &slot, FilterUnits const &/*units*/) { - NRPixBlock *in = slot.get(_input); - if (!in) { - g_warning("Missing source image for feTile (in=%d)", _input); - return 1; - } - - NRPixBlock *out = new NRPixBlock; - - nr_pixblock_setup_fast(out, in->mode, - in->area.x0, in->area.y0, in->area.x1, in->area.y1, - true); - - unsigned char *in_data = NR_PIXBLOCK_PX(in); - unsigned char *out_data = NR_PIXBLOCK_PX(out); +void FilterTile::render_cairo(FilterSlot &slot) +{ + static bool tile_warning = false; //IMPLEMENT ME! - g_warning("Renderer for feTile is not implemented."); - (void)in_data; - (void)out_data; + if (!tile_warning) { + g_warning("Renderer for feTile is not implemented."); + tile_warning = true; + } - out->empty = FALSE; - slot.set(_output, out); - return 0; + cairo_surface_t *in = slot.getcairo(_input); + slot.set(_output, in); } void FilterTile::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*trans*/) { } -FilterTraits FilterTile::get_input_traits() { - return TRAIT_PARALLER; -} - } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-tile.h b/src/display/nr-filter-tile.h index 4a2a0dddc..5c0a3e553 100644 --- a/src/display/nr-filter-tile.h +++ b/src/display/nr-filter-tile.h @@ -13,22 +13,20 @@ */ #include "display/nr-filter-primitive.h" -#include "display/nr-filter-slot.h" -#include "display/nr-filter-units.h" -#include "libnr/nr-rect-l.h" namespace Inkscape { namespace Filters { +class FilterSlot; + class FilterTile : public FilterPrimitive { public: FilterTile(); static FilterPrimitive *create(); virtual ~FilterTile(); - virtual int render(FilterSlot &slot, FilterUnits const &units); + virtual void render_cairo(FilterSlot &slot); virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); - virtual FilterTraits get_input_traits(); }; } /* namespace Filters */ diff --git a/src/display/nr-filter-turbulence.cpp b/src/display/nr-filter-turbulence.cpp index a91de0460..6aa435715 100644 --- a/src/display/nr-filter-turbulence.cpp +++ b/src/display/nr-filter-turbulence.cpp @@ -17,30 +17,293 @@ * Released under GNU GPL version 2 (or later), read the file 'COPYING' for more information */ -#include "display/nr-arena-item.h" +#include "display/cairo-templates.h" +#include "display/cairo-utils.h" #include "display/nr-filter.h" #include "display/nr-filter-turbulence.h" #include "display/nr-filter-units.h" #include "display/nr-filter-utils.h" #include "libnr/nr-rect-l.h" -#include "libnr/nr-blit.h" #include <math.h> namespace Inkscape { namespace Filters{ +class TurbulenceGenerator { +public: + TurbulenceGenerator() + : _wrapx(0) + , _wrapy(0) + , _wrapw(0) + , _wraph(0) + , _inited(false) + {} + + void init(long seed, Geom::Rect const &tile, Geom::Point const &freq, bool stitch, + bool fractalnoise, int octaves) + { + // setup random number generator + _setupSeed(seed); + + // set values + _tile = tile; + _baseFreq = freq; + _stitchTiles = stitch; + _fractalnoise = fractalnoise; + _octaves = octaves; + + int i; + for (int k = 0; k < 4; ++k) { + for (i = 0; i < BSize; ++i) { + _latticeSelector[i] = i; + + _gradient[i][k][0] = static_cast<double>(_random() % (BSize*2) - BSize) / BSize; + _gradient[i][k][1] = static_cast<double>(_random() % (BSize*2) - BSize) / BSize; + + // normalize gradient + double s = hypot(_gradient[i][k][0], _gradient[i][k][1]); + _gradient[i][k][0] /= s; + _gradient[i][k][1] /= s; + } + } + while (--i) { + // shuffle lattice selectors + int j = _random() % BSize; + std::swap(_latticeSelector[i], _latticeSelector[j]); + } + + // fill out the remaining part of the gradient + for (i = 0; i < BSize + 2; ++i) + { + _latticeSelector[BSize + i] = _latticeSelector[i]; + + for(int k = 0; k < 4; ++k) { + _gradient[BSize + i][k][0] = _gradient[i][k][0]; + _gradient[BSize + i][k][1] = _gradient[i][k][1]; + } + } + + // When stitching tiled turbulence, the frequencies must be adjusted + // so that the tile borders will be continuous. + if (_stitchTiles) { + if (_baseFreq[Geom::X] != 0.0) + { + double freq = _baseFreq[Geom::X]; + double lo = floor(_tile.width() * freq) / _tile.width(); + double hi = ceil(_tile.width() * freq) / _tile.width(); + _baseFreq[Geom::X] = freq / lo < hi / freq ? lo : hi; + } + if (_baseFreq[Geom::Y] != 0.0) + { + double freq = _baseFreq[Geom::Y]; + double lo = floor(_tile.height() * freq) / _tile.height(); + double hi = ceil(_tile.height() * freq) / _tile.height(); + _baseFreq[Geom::Y] = freq / lo < hi / freq ? lo : hi; + } + + _wrapw = _tile.width() * _baseFreq[Geom::X] + 0.5; + _wraph = _tile.height() * _baseFreq[Geom::Y] + 0.5; + _wrapx = _tile.left() * _baseFreq[Geom::X] + PerlinOffset + _wrapw; + _wrapy = _tile.top() * _baseFreq[Geom::Y] + PerlinOffset + _wraph; + } + _inited = true; + } + + G_GNUC_PURE + guint32 turbulencePixel(Geom::Point const &p) const { + int wrapx = _wrapx, wrapy = _wrapy, wrapw = _wrapw, wraph = _wraph; + + double pixel[4]; + double x = p[Geom::X] * _baseFreq[Geom::X]; + double y = p[Geom::Y] * _baseFreq[Geom::Y]; + double ratio = 1.0; + + for (int k = 0; k < 4; ++k) + pixel[k] = 0.0; + + for(int octave = 0; octave < _octaves; ++octave) + { + double tx = x + PerlinOffset; + double bx = floor(tx); + double rx0 = tx - bx, rx1 = rx0 - 1.0; + int bx0 = bx, bx1 = bx0 + 1; + + double ty = y + PerlinOffset; + double by = floor(ty); + double ry0 = ty - by, ry1 = ry0 - 1.0; + int by0 = by, by1 = by0 + 1; + + if (_stitchTiles) { + if (bx0 >= wrapx) bx0 -= wrapw; + if (bx1 >= wrapx) bx1 -= wrapw; + if (by0 >= wrapy) by0 -= wraph; + if (by1 >= wrapy) by1 -= wraph; + } + bx0 &= BMask; + bx1 &= BMask; + by0 &= BMask; + by1 &= BMask; + + int i = _latticeSelector[bx0]; + int j = _latticeSelector[bx1]; + int b00 = _latticeSelector[i + by0]; + int b01 = _latticeSelector[i + by1]; + int b10 = _latticeSelector[j + by0]; + int b11 = _latticeSelector[j + by1]; + + double sx = _scurve(rx0); + double sy = _scurve(ry0); + + double result[4]; + // channel numbering: R=0, G=1, B=2, A=3 + for (int k = 0; k < 4; ++k) { + double const *qxa = _gradient[b00][k]; + double const *qxb = _gradient[b10][k]; + double a = _lerp(sx, rx0 * qxa[0] + ry0 * qxa[1], + rx1 * qxb[0] + ry0 * qxb[1]); + double const *qya = _gradient[b01][k]; + double const *qyb = _gradient[b11][k]; + double b = _lerp(sx, rx0 * qya[0] + ry1 * qya[1], + rx1 * qyb[0] + ry1 * qyb[1]); + result[k] = _lerp(sy, a, b); + } + + if (_fractalnoise) { + for (int k = 0; k < 4; ++k) + pixel[k] += result[k] / ratio; + } else { + for (int k = 0; k < 4; ++k) + pixel[k] += fabs(result[k]) / ratio; + } + + x *= 2; + y *= 2; + ratio *= 2; + + if(_stitchTiles) + { + // Update stitch values. Subtracting PerlinOffset before the multiplication and + // adding it afterward simplifies to subtracting it once. + wrapw *= 2; + wraph *= 2; + wrapx = wrapx*2 - PerlinOffset; + wrapy = wrapy*2 - PerlinOffset; + } + } + + if (_fractalnoise) { + guint32 r = CLAMP_D_TO_U8((pixel[0]*255.0 + 255.0) / 2); + guint32 g = CLAMP_D_TO_U8((pixel[1]*255.0 + 255.0) / 2); + guint32 b = CLAMP_D_TO_U8((pixel[2]*255.0 + 255.0) / 2); + guint32 a = CLAMP_D_TO_U8((pixel[3]*255.0 + 255.0) / 2); + r = premul_alpha(r, a); + g = premul_alpha(g, a); + b = premul_alpha(b, a); + ASSEMBLE_ARGB32(pxout, a,r,g,b); + return pxout; + } else { + guint32 r = CLAMP_D_TO_U8(pixel[0]*255.0); + guint32 g = CLAMP_D_TO_U8(pixel[1]*255.0); + guint32 b = CLAMP_D_TO_U8(pixel[2]*255.0); + guint32 a = CLAMP_D_TO_U8(pixel[3]*255.0); + r = premul_alpha(r, a); + g = premul_alpha(g, a); + b = premul_alpha(b, a); + ASSEMBLE_ARGB32(pxout, a,r,g,b); + return pxout; + } + } + + //G_GNUC_PURE + /*guint32 turbulencePixel(Geom::Point const &p) const { + if (!_fractalnoise) { + guint32 r = CLAMP_D_TO_U8(turbulence(0, p)*255.0); + guint32 g = CLAMP_D_TO_U8(turbulence(1, p)*255.0); + guint32 b = CLAMP_D_TO_U8(turbulence(2, p)*255.0); + guint32 a = CLAMP_D_TO_U8(turbulence(3, p)*255.0); + r = premul_alpha(r, a); + g = premul_alpha(g, a); + b = premul_alpha(b, a); + ASSEMBLE_ARGB32(pxout, a,r,g,b); + return pxout; + } else { + guint32 r = CLAMP_D_TO_U8((turbulence(0, p)*255.0 + 255.0) / 2); + guint32 g = CLAMP_D_TO_U8((turbulence(1, p)*255.0 + 255.0) / 2); + guint32 b = CLAMP_D_TO_U8((turbulence(2, p)*255.0 + 255.0) / 2); + guint32 a = CLAMP_D_TO_U8((turbulence(3, p)*255.0 + 255.0) / 2); + r = premul_alpha(r, a); + g = premul_alpha(g, a); + b = premul_alpha(b, a); + ASSEMBLE_ARGB32(pxout, a,r,g,b); + return pxout; + } + }*/ + + bool ready() const { return _inited; } + void dirty() { _inited = false; } + +private: + void _setupSeed(long seed) { + _seed = seed; + if (_seed <= 0) _seed = -(_seed % (RAND_m - 1)) + 1; + if (_seed > RAND_m - 1) _seed = RAND_m - 1; + } + long _random() { + /* Produces results in the range [1, 2**31 - 2]. + * Algorithm is: r = (a * r) mod m + * where a = 16807 and m = 2**31 - 1 = 2147483647 + * See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988 + * To test: the algorithm should produce the result 1043618065 + * as the 10,000th generated number if the original seed is 1. */ + _seed = RAND_a * (_seed % RAND_q) - RAND_r * (_seed / RAND_q); + if (_seed <= 0) _seed += RAND_m; + return _seed; + } + static inline double _scurve(double t) { + return t * t * (3.0 - 2.0*t); + } + static inline double _lerp(double t, double a, double b) { + return a + t * (b-a); + } + + // random number generator constants + static long const + RAND_m = 2147483647, // 2**31 - 1 + RAND_a = 16807, // 7**5; primitive root of m + RAND_q = 127773, // m / a + RAND_r = 2836; // m % a + + // other constants + static int const + BSize = 0x100, + BMask = 0xff; + static double const + PerlinOffset = 4096.0; + + Geom::Rect _tile; + Geom::Point _baseFreq; + int _latticeSelector[2*BSize + 2]; + double _gradient[2*BSize + 2][4][2]; + long _seed; + int _octaves; + bool _stitchTiles; + int _wrapx, _wrapy, _wrapw, _wraph; + bool _inited; + bool _fractalnoise; +}; + FilterTurbulence::FilterTurbulence() -: XbaseFrequency(0), - YbaseFrequency(0), - numOctaves(1), - seed(0), - updated(false), - updated_area(NR::IPoint(), NR::IPoint()), - pix(NULL), - fTileWidth(10), //guessed - fTileHeight(10), //guessed - fTileX(1), //guessed - fTileY(1) //guessed + : gen(new TurbulenceGenerator()) + , XbaseFrequency(0) + , YbaseFrequency(0) + , numOctaves(1) + , seed(0) + , updated(false) + , updated_area(NR::IPoint(), NR::IPoint()) + , fTileWidth(10) //guessed + , fTileHeight(10) //guessed + , fTileX(1) //guessed + , fTileY(1) //guessed { } @@ -50,305 +313,79 @@ FilterPrimitive * FilterTurbulence::create() { FilterTurbulence::~FilterTurbulence() { - if (pix) { - nr_pixblock_release(pix); - delete pix; - } + delete gen; } void FilterTurbulence::set_baseFrequency(int axis, double freq){ if (axis==0) XbaseFrequency=freq; if (axis==1) YbaseFrequency=freq; + gen->dirty(); } void FilterTurbulence::set_numOctaves(int num){ - numOctaves=num; + numOctaves = num; + gen->dirty(); } void FilterTurbulence::set_seed(double s){ - seed=s; + seed = s; + gen->dirty(); } void FilterTurbulence::set_stitchTiles(bool st){ - stitchTiles=st; + stitchTiles = st; + gen->dirty(); } void FilterTurbulence::set_type(FilterTurbulenceType t){ - type=t; + type = t; + gen->dirty(); } void FilterTurbulence::set_updated(bool u){ - updated=u; } -void FilterTurbulence::render_area(NRPixBlock *pix, NR::IRect &full_area, FilterUnits const &units) { - const int bbox_x0 = full_area.min()[NR::X]; - const int bbox_y0 = full_area.min()[NR::Y]; - const int bbox_x1 = full_area.max()[NR::X]; - const int bbox_y1 = full_area.max()[NR::Y]; - - Geom::Affine unit_trans = units.get_matrix_primitiveunits2pb().inverse(); - - double point[2]; - - unsigned char *pb = NR_PIXBLOCK_PX(pix); - - if (type==TURBULENCE_TURBULENCE){ - for (int y = std::max(bbox_y0, pix->area.y0); y < std::min(bbox_y1, pix->area.y1); y++){ - int out_line = (y - pix->area.y0) * pix->rs; - point[1] = y * unit_trans[3] + unit_trans[5]; - for (int x = std::max(bbox_x0, pix->area.x0); x < std::min(bbox_x1, pix->area.x1); x++){ - int out_pos = out_line + 4 * (x - pix->area.x0); - point[0] = x * unit_trans[0] + unit_trans[4]; - pb[out_pos] = CLAMP_D_TO_U8( turbulence(0,point)*255 ); // CLAMP includes rounding! - pb[out_pos + 1] = CLAMP_D_TO_U8( turbulence(1,point)*255 ); - pb[out_pos + 2] = CLAMP_D_TO_U8( turbulence(2,point)*255 ); - pb[out_pos + 3] = CLAMP_D_TO_U8( turbulence(3,point)*255 ); - } - } - } else { - for (int y = std::max(bbox_y0, pix->area.y0); y < std::min(bbox_y1, pix->area.y1); y++){ - int out_line = (y - pix->area.y0) * pix->rs; - point[1] = y * unit_trans[3] + unit_trans[5]; - for (int x = std::max(bbox_x0, pix->area.x0); x < std::min(bbox_x1, pix->area.x1); x++){ - int out_pos = out_line + 4 * (x - pix->area.x0); - point[0] = x * unit_trans[0] + unit_trans[4]; - pb[out_pos] = CLAMP_D_TO_U8( ((turbulence(0,point)*255) +255)/2 ); - pb[out_pos + 1] = CLAMP_D_TO_U8( ((turbulence(1,point)*255)+255)/2 ); - pb[out_pos + 2] = CLAMP_D_TO_U8( ((turbulence(2,point)*255) +255)/2 ); - pb[out_pos + 3] = CLAMP_D_TO_U8( ((turbulence(3,point)*255) +255)/2 ); - } - } +struct Turbulence { + Turbulence(TurbulenceGenerator const &gen, Geom::Affine const &trans, int x0, int y0) + : _gen(gen) + , _trans(trans) + , _x0(x0), _y0(y0) + {} + guint32 operator()(int x, int y) { + Geom::Point point(x + _x0, y + _y0); + point *= _trans; + return _gen.turbulencePixel(point); } +private: + TurbulenceGenerator const &_gen; + Geom::Affine _trans; + int _x0, _y0; +}; - pix->empty = FALSE; -} - -void FilterTurbulence::update_pixbuffer(NR::IRect &area, FilterUnits const &units) { - int bbox_x0 = area.min()[NR::X]; - int bbox_y0 = area.min()[NR::Y]; - int bbox_x1 = area.max()[NR::X]; - int bbox_y1 = area.max()[NR::Y]; - - TurbulenceInit((long)seed); - - if (!pix){ - pix = new NRPixBlock; - nr_pixblock_setup_fast(pix, NR_PIXBLOCK_MODE_R8G8B8A8N, bbox_x0, bbox_y0, bbox_x1, bbox_y1, true); - } - else if (bbox_x0 != pix->area.x0 || bbox_y0 != pix->area.y0 || - bbox_x1 != pix->area.x1 || bbox_y1 != pix->area.y1) - { - /* TODO: release-setup cycle not actually needed, if pixblock - * width and height don't change */ - nr_pixblock_release(pix); - nr_pixblock_setup_fast(pix, NR_PIXBLOCK_MODE_R8G8B8A8N, bbox_x0, bbox_y0, bbox_x1, bbox_y1, true); - } - - /* This limits pre-rendered turbulence to two megapixels. This is - * arbitary limit and could be something other, too. - * If bigger area is needed, visible area is rendered on demand. */ - if (!pix || (pix->size != NR_PIXBLOCK_SIZE_TINY && pix->data.px == NULL) || - ((bbox_x1 - bbox_x0) * (bbox_y1 - bbox_y0) > 2*1024*1024)) { - pix_data = NULL; - return; +void FilterTurbulence::render_cairo(FilterSlot &slot) +{ + cairo_surface_t *input = slot.getcairo(_input); + cairo_surface_t *out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_COLOR_ALPHA); + + if (!gen->ready()) { + Geom::Point ta(fTileX, fTileY); + Geom::Point tb(fTileX + fTileWidth, fTileY + fTileHeight); + gen->init(seed, Geom::Rect(ta, tb), + Geom::Point(XbaseFrequency, YbaseFrequency), stitchTiles, + type == TURBULENCE_FRACTALNOISE, numOctaves); } - render_area(pix, area, units); - - pix_data = NR_PIXBLOCK_PX(pix); - - updated=true; - updated_area = area; -} + Geom::Affine unit_trans = slot.get_units().get_matrix_primitiveunits2pb().inverse(); + Geom::Rect slot_area = slot.get_slot_area(); + double x0 = slot_area.min()[Geom::X]; + double y0 = slot_area.min()[Geom::Y]; -int FilterTurbulence::render(FilterSlot &slot, FilterUnits const &units) { - NR::IRect area = units.get_pixblock_filterarea_paraller(); - // TODO: could be faster - updated_area only has to be same size as area - if (!updated || updated_area != area) update_pixbuffer(area, units); + ink_cairo_surface_synthesize(out, Turbulence(*gen, unit_trans, x0, y0)); - NRPixBlock *in = slot.get(_input); - if (!in) { - g_warning("Missing source image for feTurbulence (in=%d)", _input); - return 1; - } + cairo_surface_mark_dirty(out); - NRPixBlock *out = new NRPixBlock; - int x0 = in->area.x0, y0 = in->area.y0; - int x1 = in->area.x1, y1 = in->area.y1; - nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8N, x0, y0, x1, y1, true); - - if (pix_data) { - /* If pre-rendered output of whole filter area exists, just copy it. */ - nr_blit_pixblock_pixblock(out, pix); - } else { - /* No pre-rendered output, render the required area here. */ - render_area(out, area, units); - } - - out->empty = FALSE; slot.set(_output, out); - return 0; -} - -long FilterTurbulence::Turbulence_setup_seed(long lSeed) -{ - if (lSeed <= 0) lSeed = -(lSeed % (RAND_m - 1)) + 1; - if (lSeed > RAND_m - 1) lSeed = RAND_m - 1; - return lSeed; -} - -long FilterTurbulence::TurbulenceRandom(long lSeed) -{ - long result; - result = RAND_a * (lSeed % RAND_q) - RAND_r * (lSeed / RAND_q); - if (result <= 0) result += RAND_m; - return result; -} - -void FilterTurbulence::TurbulenceInit(long lSeed) -{ - double s; - int i, j, k; - lSeed = Turbulence_setup_seed(lSeed); - for(k = 0; k < 4; k++) - { - for(i = 0; i < BSize; i++) - { - uLatticeSelector[i] = i; - for (j = 0; j < 2; j++) - fGradient[k][i][j] = (double)(((lSeed = TurbulenceRandom(lSeed)) % (BSize + BSize)) - BSize) / BSize; - s = double(sqrt(fGradient[k][i][0] * fGradient[k][i][0] + fGradient[k][i][1] * fGradient[k][i][1])); - fGradient[k][i][0] /= s; - fGradient[k][i][1] /= s; - } - } - while(--i) - { - k = uLatticeSelector[i]; - uLatticeSelector[i] = uLatticeSelector[j = (lSeed = TurbulenceRandom(lSeed)) % BSize]; - uLatticeSelector[j] = k; - } - for(i = 0; i < BSize + 2; i++) - { - uLatticeSelector[BSize + i] = uLatticeSelector[i]; - for(k = 0; k < 4; k++) - for(j = 0; j < 2; j++) - fGradient[k][BSize + i][j] = fGradient[k][i][j]; - } -} - -double FilterTurbulence::TurbulenceNoise2(int nColorChannel, double vec[2], StitchInfo *pStitchInfo) -{ - int bx0, bx1, by0, by1, b00, b10, b01, b11; - double rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v; - int i, j; - t = vec[0] + PerlinN; - bx0 = (int)t; - bx1 = bx0+1; - rx0 = t - (int)t; - rx1 = rx0 - 1.0f; - t = vec[1] + PerlinN; - by0 = (int)t; - by1 = by0+1; - ry0 = t - (int)t; - ry1 = ry0 - 1.0f; - // If stitching, adjust lattice points accordingly. - if(pStitchInfo != NULL) - { - if(bx0 >= pStitchInfo->nWrapX) - bx0 -= pStitchInfo->nWidth; - if(bx1 >= pStitchInfo->nWrapX) - bx1 -= pStitchInfo->nWidth; - if(by0 >= pStitchInfo->nWrapY) - by0 -= pStitchInfo->nHeight; - if(by1 >= pStitchInfo->nWrapY) - by1 -= pStitchInfo->nHeight; - } - bx0 &= BM; - bx1 &= BM; - by0 &= BM; - by1 &= BM; - i = uLatticeSelector[bx0]; - j = uLatticeSelector[bx1]; - b00 = uLatticeSelector[i + by0]; - b10 = uLatticeSelector[j + by0]; - b01 = uLatticeSelector[i + by1]; - b11 = uLatticeSelector[j + by1]; - sx = double(s_curve(rx0)); - sy = double(s_curve(ry0)); - q = fGradient[nColorChannel][b00]; u = rx0 * q[0] + ry0 * q[1]; - q = fGradient[nColorChannel][b10]; v = rx1 * q[0] + ry0 * q[1]; - a = turb_lerp(sx, u, v); - q = fGradient[nColorChannel][b01]; u = rx0 * q[0] + ry1 * q[1]; - q = fGradient[nColorChannel][b11]; v = rx1 * q[0] + ry1 * q[1]; - b = turb_lerp(sx, u, v); - return turb_lerp(sy, a, b); -} - -double FilterTurbulence::turbulence(int nColorChannel, double *point) -{ - StitchInfo stitch; - StitchInfo *pStitchInfo = NULL; // Not stitching when NULL. - // Adjust the base frequencies if necessary for stitching. - if(stitchTiles) - { - // When stitching tiled turbulence, the frequencies must be adjusted - // so that the tile borders will be continuous. - if(XbaseFrequency != 0.0) - { - double fLoFreq = double(floor(fTileWidth * XbaseFrequency)) / fTileWidth; - double fHiFreq = double(ceil(fTileWidth * XbaseFrequency)) / fTileWidth; - if(XbaseFrequency / fLoFreq < fHiFreq / XbaseFrequency) - XbaseFrequency = fLoFreq; - else - XbaseFrequency = fHiFreq; - } - if(YbaseFrequency != 0.0) - { - double fLoFreq = double(floor(fTileHeight * YbaseFrequency)) / fTileHeight; - double fHiFreq = double(ceil(fTileHeight * YbaseFrequency)) / fTileHeight; - if(YbaseFrequency / fLoFreq < fHiFreq / YbaseFrequency) - YbaseFrequency = fLoFreq; - else - YbaseFrequency = fHiFreq; - } - // Set up TurbulenceInitial stitch values. - pStitchInfo = &stitch; - stitch.nWidth = int(fTileWidth * XbaseFrequency + 0.5f); - stitch.nWrapX = int(fTileX * XbaseFrequency + PerlinN + stitch.nWidth); - stitch.nHeight = int(fTileHeight * YbaseFrequency + 0.5f); - stitch.nWrapY = int(fTileY * YbaseFrequency + PerlinN + stitch.nHeight); - } - double fSum = 0.0f; - double vec[2]; - vec[0] = point[0] * XbaseFrequency; - vec[1] = point[1] * YbaseFrequency; - double ratio = 1; - for(int nOctave = 0; nOctave < numOctaves; nOctave++) - { - if(type==TURBULENCE_FRACTALNOISE) - fSum += double(TurbulenceNoise2(nColorChannel, vec, pStitchInfo) / ratio); - else - fSum += double(fabs(TurbulenceNoise2(nColorChannel, vec, pStitchInfo)) / ratio); - vec[0] *= 2; - vec[1] *= 2; - ratio *= 2; - if(pStitchInfo != NULL) - { - // Update stitch values. Subtracting PerlinN before the multiplication and - // adding it afterward simplifies to subtracting it once. - stitch.nWidth *= 2; - stitch.nWrapX = 2 * stitch.nWrapX - PerlinN; - stitch.nHeight *= 2; - stitch.nWrapY = 2 * stitch.nWrapY - PerlinN; - } - } - return fSum; -} - -FilterTraits FilterTurbulence::get_input_traits() { - return TRAIT_PARALLER; + cairo_surface_destroy(out); } } /* namespace Filters */ diff --git a/src/display/nr-filter-turbulence.h b/src/display/nr-filter-turbulence.h index ee870f758..50161b6be 100644 --- a/src/display/nr-filter-turbulence.h +++ b/src/display/nr-filter-turbulence.h @@ -21,6 +21,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <2geom/point.h> #include "display/nr-filter-primitive.h" #include "display/nr-filter-slot.h" #include "display/nr-filter-units.h" @@ -35,32 +36,7 @@ enum FilterTurbulenceType { TURBULENCE_ENDTYPE }; -struct StitchInfo -{ - int nWidth; // How much to subtract to wrap for stitching. - int nHeight; - int nWrapX; // Minimum value to wrap. - int nWrapY; -}; - -/* Produces results in the range [1, 2**31 - 2]. -Algorithm is: r = (a * r) mod m -where a = 16807 and m = 2**31 - 1 = 2147483647 -See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988 -To test: the algorithm should produce the result 1043618065 -as the 10,000th generated number if the original seed is 1. -*/ -#define RAND_m 2147483647 /* 2**31 - 1 */ -#define RAND_a 16807 /* 7**5; primitive root of m */ -#define RAND_q 127773 /* m / a */ -#define RAND_r 2836 /* m % a */ -#define BSize 0x100 -#define BM 0xff -#define PerlinN 0x1000 -#define NP 12 /* 2^PerlinN */ -#define NM 0xfff -#define s_curve(t) ( t * t * (3. - 2. * t) ) -#define turb_lerp(t, a, b) ( a + t * (b - a) ) +class TurbulenceGenerator; class FilterTurbulence : public FilterPrimitive { public: @@ -68,9 +44,7 @@ public: static FilterPrimitive *create(); virtual ~FilterTurbulence(); - virtual int render(FilterSlot &slot, FilterUnits const &units); - void update_pixbuffer(NR::IRect &area, FilterUnits const &units); - void render_area(NRPixBlock *pix, NR::IRect &full_area, FilterUnits const &units); + virtual void render_cairo(FilterSlot &slot); void set_baseFrequency(int axis, double freq); void set_numOctaves(int num); @@ -78,14 +52,11 @@ public: void set_stitchTiles(bool st); void set_type(FilterTurbulenceType t); void set_updated(bool u); - virtual FilterTraits get_input_traits(); private: - long Turbulence_setup_seed(long lSeed); - long TurbulenceRandom(long lSeed); - void TurbulenceInit(long lSeed); - double TurbulenceNoise2(int nColorChannel, double vec[2], StitchInfo *pStitchInfo); - double turbulence(int nColorChannel, double *point); + TurbulenceGenerator *gen; + + void turbulenceInit(long seed); double XbaseFrequency, YbaseFrequency; int numOctaves; @@ -94,17 +65,14 @@ private: FilterTurbulenceType type; bool updated; NR::IRect updated_area; - NRPixBlock *pix; unsigned char *pix_data; - int uLatticeSelector[BSize + BSize + 2]; - double fGradient[4][BSize + BSize + 2][2]; - double fTileWidth; double fTileHeight; double fTileX; double fTileY; + }; } /* namespace Filters */ diff --git a/src/display/nr-filter-units.h b/src/display/nr-filter-units.h index b78e102cd..2fc3e5533 100644 --- a/src/display/nr-filter-units.h +++ b/src/display/nr-filter-units.h @@ -13,8 +13,6 @@ */ #include "sp-filter-units.h" -#include "libnr/nr-matrix.h" -#include "libnr/nr-rect.h" #include "libnr/nr-rect-l.h" #include <2geom/affine.h> #include <2geom/rect.h> @@ -22,6 +20,18 @@ namespace Inkscape { namespace Filters { +/* Notes: + * - "filter units" is a coordinate system where the filter region is contained + * between (0,0) and (1,1). Do not confuse this with the filterUnits property + * - "primitive units" is the coordinate system in which all lengths and distances + * in the filter definition should be interpreted. They are affected by the value + * of the primitiveUnits attribute + * - "pb" is the coordinate system in which filter rendering happens. + * It might be aligned with user or screen coordinates depending on + * the filter primitives used in the filter. + * - "display" are world coordinates of the canvas - pixel grid coordinates + * of the drawing area translated so that (0,0) corresponds to the document origin + */ class FilterUnits { public: FilterUnits(); diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index 85815c31a..55190b00c 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -15,6 +15,7 @@ #include <cmath> #include <cstring> #include <string> +#include <cairo.h> #include "display/nr-filter.h" #include "display/nr-filter-primitive.h" @@ -41,8 +42,6 @@ #include "display/nr-arena.h" #include "display/nr-arena-item.h" -#include "libnr/nr-pixblock.h" -#include "libnr/nr-blit.h" #include <2geom/affine.h> #include <2geom/rect.h> #include "svg/svg-length.h" @@ -60,43 +59,14 @@ namespace Filters { using Geom::X; using Geom::Y; -static Geom::OptRect get_item_bbox(NRArenaItem const *item) { - Geom::Rect item_bbox; - if (item->item_bbox) { - item_bbox = *(item->item_bbox); - } else { - // Bounding box might not exist, so create a dummy one. - Geom::Point zero(0, 0); - item_bbox = Geom::Rect(zero, zero); - } - if (item_bbox.min()[X] > item_bbox.max()[X] - || item_bbox.min()[Y] > item_bbox.max()[Y]) - { - // In case of negative-size bbox, return an empty OptRect - return Geom::OptRect(); - } - return Geom::OptRect(item_bbox); -} - Filter::Filter() { - _primitive_count = 0; - _primitive_table_size = 1; - _primitive = new FilterPrimitive*[1]; - _primitive[0] = NULL; - //_primitive_count = 1; - //_primitive[0] = new FilterGaussian; _common_init(); } Filter::Filter(int n) { - _primitive_count = 0; - _primitive_table_size = (n > 0) ? n : 1; // we guarantee there is at least 1(one) filter slot - _primitive = new FilterPrimitive*[_primitive_table_size]; - for ( int i = 0 ; i < _primitive_table_size ; i++ ) { - _primitive[i] = NULL; - } + if (n > 0) _primitive.reserve(n); _common_init(); } @@ -125,51 +95,56 @@ void Filter::_common_init() { Filter::~Filter() { clear_primitives(); - delete[] _primitive; } -int Filter::render(NRArenaItem const *item, NRPixBlock *pb) +int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea, cairo_t *graphic, NRRectL const *area) { - if (!_primitive[0]) { - // TODO: Should clear the input buffer instead of just returning - return 1; + if (_primitive.empty()) { + // when no primitives are defined, clear source graphic + cairo_set_source_rgba(graphic, 0,0,0,0); + cairo_set_operator(graphic, CAIRO_OPERATOR_SOURCE); + cairo_paint(graphic); + cairo_set_operator(graphic, CAIRO_OPERATOR_OVER); + return 1; } FilterQuality const filterquality = (FilterQuality)item->arena->filterquality; int const blurquality = item->arena->blurquality; Geom::Affine trans = item->ctm; - FilterSlot slot(_slot_count, item); - slot.set_quality(filterquality); - slot.set_blurquality(blurquality); Geom::Rect item_bbox; { - Geom::OptRect maybe_bbox = get_item_bbox(item); + Geom::OptRect maybe_bbox = item->item_bbox; if (maybe_bbox.isEmpty()) { // Code below needs a bounding box return 1; } item_bbox = *maybe_bbox; } - - Geom::Rect filter_area = filter_effect_area(item_bbox); if (item_bbox.hasZeroArea()) { // It's no use to try and filter an empty object. return 1; } + Geom::Rect filter_area = filter_effect_area(item_bbox); FilterUnits units(_filter_units, _primitive_units); units.set_ctm(trans); units.set_item_bbox(item_bbox); units.set_filter_area(filter_area); - // TODO: with filterRes of 0x0 should return an empty image std::pair<double,double> resolution = _filter_resolution(filter_area, trans, filterquality); - if(!(resolution.first > 0 && resolution.second > 0)) - return 1; + if (!(resolution.first > 0 && resolution.second > 0)) { + // zero resolution - clear source graphic and return + cairo_set_source_rgba(graphic, 0,0,0,0); + cairo_set_operator(graphic, CAIRO_OPERATOR_SOURCE); + cairo_paint(graphic); + cairo_set_operator(graphic, CAIRO_OPERATOR_OVER); + return 1; + } + units.set_resolution(resolution.first, resolution.second); if (_x_pixels > 0) { units.set_automatic_resolution(false); @@ -179,47 +154,29 @@ int Filter::render(NRArenaItem const *item, NRPixBlock *pb) } units.set_paraller(false); - for (int i = 0 ; i < _primitive_count ; i++) { - if (_primitive[i]->get_input_traits() & TRAIT_PARALLER) { + Geom::Affine pbtrans = units.get_matrix_display2pb(); + for (unsigned i = 0 ; i < _primitive.size() ; i++) { + if (!_primitive[i]->can_handle_affine(pbtrans)) { units.set_paraller(true); break; } } - slot.set_units(units); - - NRPixBlock *in = new NRPixBlock; - nr_pixblock_setup_fast(in, pb->mode, pb->area.x0, pb->area.y0, - pb->area.x1, pb->area.y1, true); - if (in->size != NR_PIXBLOCK_SIZE_TINY && in->data.px == NULL) { - g_warning("Inkscape::Filters::Filter::render: failed to reserve temporary buffer"); - return 0; - } - nr_blit_pixblock_pixblock(in, pb); - in->empty = FALSE; - slot.set(NR_FILTER_SOURCEGRAPHIC, in); - - // Check that we are rendering a non-empty area - in = slot.get(NR_FILTER_SOURCEGRAPHIC); - if (in->area.x1 - in->area.x0 <= 0 || in->area.y1 - in->area.y0 <= 0) { - if (in->area.x1 - in->area.x0 < 0 || in->area.y1 - in->area.y0 < 0) { - g_warning("Inkscape::Filters::Filter::render: negative area! (%d, %d) (%d, %d)", - in->area.x0, in->area.y0, in->area.x1, in->area.y1); - } - return 0; - } - in = NULL; // in is now handled by FilterSlot, we should not touch it + FilterSlot slot(const_cast<NRArenaItem*>(item), bgct, bgarea, cairo_get_target(graphic), area, units); + slot.set_quality(filterquality); + slot.set_blurquality(blurquality); - for (int i = 0 ; i < _primitive_count ; i++) { - _primitive[i]->render(slot, units); + for (unsigned i = 0 ; i < _primitive.size() ; i++) { + _primitive[i]->render_cairo(slot); } - slot.get_final(_output_slot, pb); + cairo_surface_t *result = slot.get_result(_output_slot); + cairo_set_source_surface(graphic, result, area->x0, area->y0); + cairo_set_operator(graphic, CAIRO_OPERATOR_SOURCE); + cairo_paint(graphic); + cairo_set_operator(graphic, CAIRO_OPERATOR_OVER); + cairo_surface_destroy(result); - // 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; } @@ -232,9 +189,10 @@ void Filter::set_primitive_units(SPFilterUnits unit) { } void Filter::area_enlarge(NRRectL &bbox, NRArenaItem const *item) const { - for (int i = 0 ; i < _primitive_count ; i++) { + for (unsigned i = 0 ; i < _primitive.size() ; i++) { if (_primitive[i]) _primitive[i]->area_enlarge(bbox, item->ctm); } + /* TODO: something. See images at the bottom of filters.svg with medium-low filtering quality. @@ -248,7 +206,7 @@ void Filter::area_enlarge(NRRectL &bbox, NRArenaItem const *item) const { } Geom::Rect item_bbox; - Geom::OptRect maybe_bbox = get_item_bbox(item); + Geom::OptRect maybe_bbox = item->item_bbox; if (maybe_bbox.isEmpty()) { // Code below needs a bounding box return; @@ -268,30 +226,29 @@ void Filter::area_enlarge(NRRectL &bbox, NRArenaItem const *item) const { */ } -void Filter::bbox_enlarge(NRRectL &bbox) { +void Filter::compute_drawbox(NRArenaItem const *item, NRRectL &item_bbox) { // Modifying empty bounding boxes confuses rest of the renderer, so // let's not do that. - if (bbox.x0 > bbox.x1 || bbox.y0 > bbox.y1) return; + if (item_bbox.x0 > item_bbox.x1 || item_bbox.y0 > item_bbox.y1) return; - /* TODO: this is wrong. Should use bounding box in user coordinates - * and find its extents in display coordinates. */ - Geom::Point min(bbox.x0, bbox.y0); - Geom::Point max(bbox.x1, bbox.y1); + Geom::Point min(item_bbox.x0, item_bbox.y0); + Geom::Point max(item_bbox.x1, item_bbox.y1); Geom::Rect tmp_bbox(min, max); Geom::Rect enlarged = filter_effect_area(tmp_bbox); + enlarged = enlarged * item->ctm; - bbox.x0 = (NR::ICoord)enlarged.min()[X]; - bbox.y0 = (NR::ICoord)enlarged.min()[Y]; - bbox.x1 = (NR::ICoord)enlarged.max()[X]; - bbox.y1 = (NR::ICoord)enlarged.max()[Y]; + item_bbox.x0 = (NR::ICoord) floor(enlarged.min()[X]); + item_bbox.y0 = (NR::ICoord) floor(enlarged.min()[Y]); + item_bbox.x1 = (NR::ICoord) ceil(enlarged.max()[X]); + item_bbox.y1 = (NR::ICoord) ceil(enlarged.max()[Y]); } Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox) { Geom::Point minp, maxp; - double len_x = bbox.max()[X] - bbox.min()[X]; - double len_y = bbox.max()[Y] - bbox.min()[Y]; + double len_x = bbox.width(); + double len_y = bbox.height(); /* TODO: fetch somehow the object ex and em lengths */ _region_x.update(12, 6, len_x); _region_y.update(12, 6, len_y); @@ -367,27 +324,6 @@ void Filter::_create_constructor_table() 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++) { - new_tbl[i] = _primitive[i]; - } - _primitive_table_size *= 2; - for (int i = _primitive_count ; i < _primitive_table_size ; i++) { - new_tbl[i] = NULL; - } - if(_primitive != NULL) { - delete[] _primitive; - } else { - g_warning("oh oh"); - } - _primitive = new_tbl; -} - int Filter::add_primitive(FilterPrimitiveType type) { _create_constructor_table(); @@ -398,14 +334,8 @@ int Filter::add_primitive(FilterPrimitiveType type) if (!_constructor[type]) return -1; FilterPrimitive *created = _constructor[type](); - // If there is no space for new filter primitive, enlarge the table - if (_primitive_count >= _primitive_table_size) { - _enlarge_primitive_table(); - } - - _primitive[_primitive_count] = created; - int handle = _primitive_count; - _primitive_count++; + int handle = _primitive.size(); + _primitive.push_back(created); return handle; } @@ -415,8 +345,7 @@ int Filter::replace_primitive(int target, FilterPrimitiveType type) // Check that target is valid primitive inside this filter if (target < 0) return -1; - if (target >= _primitive_count) return -1; - if (!_primitive[target]) return -1; + if (static_cast<unsigned>(target) >= _primitive.size()) return -1; // Check that we can create a new filter of specified type if (type < 0 || type >= NR_FILTER_ENDPRIMITIVETYPE) @@ -424,27 +353,22 @@ int Filter::replace_primitive(int target, FilterPrimitiveType type) if (!_constructor[type]) return -1; FilterPrimitive *created = _constructor[type](); - // If there is no space for new filter primitive, enlarge the table - if (_primitive_count >= _primitive_table_size) { - _enlarge_primitive_table(); - } - delete _primitive[target]; _primitive[target] = created; return target; } FilterPrimitive *Filter::get_primitive(int handle) { - if (handle < 0 || handle >= _primitive_count) return NULL; + if (handle < 0 || handle >= static_cast<int>(_primitive.size())) return NULL; return _primitive[handle]; } void Filter::clear_primitives() { - for (int i = 0 ; i < _primitive_count ; i++) { - if (_primitive[i]) delete _primitive[i]; + for (unsigned i = 0 ; i < _primitive.size() ; i++) { + delete _primitive[i]; } - _primitive_count = 0; + _primitive.clear(); } void Filter::set_x(SVGLength const &length) diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h index ae5f96420..e1d4c10e5 100644 --- a/src/display/nr-filter.h +++ b/src/display/nr-filter.h @@ -13,10 +13,9 @@ */ //#include "display/nr-arena-item.h" +#include <cairo.h> #include "display/nr-filter-primitive.h" #include "display/nr-filter-types.h" -#include "libnr/nr-pixblock.h" -#include "libnr/nr-matrix.h" #include "libnr/nr-rect.h" #include "svg/svg-length.h" #include "sp-filter-units.h" @@ -29,7 +28,12 @@ namespace Filters { class Filter : public Inkscape::GC::Managed<> { public: - int render(NRArenaItem const *item, NRPixBlock *pb); + /** Given background state from @a bgct and an intermediate rendering from the surface + * backing @a graphic, modify the contents of the surface backing @a graphic to represent + * the results of filter rendering. @a bgarea and @a area specify bounding boxes + * of both surfaces in world coordinates; Cairo contexts are assumed to be in default state + * (0,0 = surface origin, no path, OVER operator) */ + int render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea, cairo_t *graphic, NRRectL const *area); /** * Creates a new filter primitive under this filter object. @@ -147,10 +151,11 @@ public: */ void area_enlarge(NRRectL &area, NRArenaItem const *item) const; /** - * Given an object bounding box, this function enlarges it so that - * it contains the filter effect area. + * Given an item bounding box (in user coords), this function enlarges it + * to contain the filter effects region and transforms it to screen + * coordinates */ - void bbox_enlarge(NRRectL &bbox); + void compute_drawbox(NRArenaItem const *item, NRRectL &item_bbox); /** * Returns the filter effects area in user coordinate system. * The given bounding box should be a bounding box as specified in @@ -170,9 +175,7 @@ public: virtual ~Filter(); private: - int _primitive_count; - int _primitive_table_size; - + std::vector<FilterPrimitive*> _primitive; /** Amount of image slots used, when this filter was rendered last time */ int _slot_count; @@ -194,10 +197,7 @@ private: SPFilterUnits _filter_units; SPFilterUnits _primitive_units; - FilterPrimitive ** _primitive; - void _create_constructor_table(); - void _enlarge_primitive_table(); void _common_init(); int _resolution_limit(FilterQuality const quality) const; std::pair<double,double> _filter_resolution(Geom::Rect const &area, diff --git a/src/display/nr-light.cpp b/src/display/nr-light.cpp index 74d83da70..65912470d 100644 --- a/src/display/nr-light.cpp +++ b/src/display/nr-light.cpp @@ -13,12 +13,12 @@ #include <cmath> -#include "libnr/nr-pixops.h" #include "display/nr-light.h" #include "display/nr-3dutils.h" #include "filters/distantlight.h" #include "filters/pointlight.h" #include "filters/spotlight.h" +#include "color.h" namespace Inkscape { namespace Filters { @@ -38,9 +38,9 @@ void DistantLight::light_vector(NR::Fvector &v) { } void DistantLight::light_components(NR::Fvector &lc) { - lc[LIGHT_RED] = NR_RGBA32_R(color); - lc[LIGHT_GREEN] = NR_RGBA32_G(color); - lc[LIGHT_BLUE] = NR_RGBA32_B(color); + lc[LIGHT_RED] = SP_RGBA32_R_U(color); + lc[LIGHT_GREEN] = SP_RGBA32_G_U(color); + lc[LIGHT_BLUE] = SP_RGBA32_B_U(color); } PointLight::PointLight(SPFePointLight *light, guint32 lighting_color, const Geom::Affine &trans) { @@ -61,9 +61,9 @@ void PointLight::light_vector(NR::Fvector &v, gdouble x, gdouble y, gdouble z) { } void PointLight::light_components(NR::Fvector &lc) { - lc[LIGHT_RED] = NR_RGBA32_R(color); - lc[LIGHT_GREEN] = NR_RGBA32_G(color); - lc[LIGHT_BLUE] = NR_RGBA32_B(color); + lc[LIGHT_RED] = SP_RGBA32_R_U(color); + lc[LIGHT_GREEN] = SP_RGBA32_G_U(color); + lc[LIGHT_BLUE] = SP_RGBA32_B_U(color); } SpotLight::SpotLight(SPFeSpotLight *light, guint32 lighting_color, const Geom::Affine &trans) { @@ -101,9 +101,9 @@ void SpotLight::light_components(NR::Fvector &lc, const NR::Fvector &L) { spmod = 0; else spmod = std::pow(spmod, speExp); - lc[LIGHT_RED] = spmod * NR_RGBA32_R(color); - lc[LIGHT_GREEN] = spmod * NR_RGBA32_G(color); - lc[LIGHT_BLUE] = spmod * NR_RGBA32_B(color); + lc[LIGHT_RED] = spmod * SP_RGBA32_R_U(color); + lc[LIGHT_GREEN] = spmod * SP_RGBA32_G_U(color); + lc[LIGHT_BLUE] = spmod * SP_RGBA32_B_U(color); } } /* namespace Filters */ diff --git a/src/display/nr-plain-stuff-gdk.cpp b/src/display/nr-plain-stuff-gdk.cpp deleted file mode 100644 index d5b43f4ea..000000000 --- a/src/display/nr-plain-stuff-gdk.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#define __NR_PLAIN_STUFF_GDK_C__ - -/* - * Miscellaneous simple rendering utilities - * - * Author: - * Lauris Kaplinski <lauris@ximian.com> - * - * Copyright (C) 2001 Lauris Kaplinski and Ximian, Inc. - * - * Released under GNU GPL - */ - -#include <libnr/nr-pixblock-pattern.h> -#include "nr-plain-stuff.h" -#include "nr-plain-stuff-gdk.h" - -void -nr_gdk_draw_rgba32_solid (GdkDrawable *drawable, GdkGC *gc, gint x, gint y, gint w, gint h, guint32 rgba) -{ - NRPixBlock pb; - - nr_pixblock_setup_fast (&pb, NR_PIXBLOCK_MODE_R8G8B8A8N, 0, 0, w, h, FALSE); - - nr_render_rgba32_rgb (NR_PIXBLOCK_PX (&pb), w, h, pb.rs, x, y, rgba); - gdk_draw_rgb_image (drawable, gc, x, y, w, h, GDK_RGB_DITHER_MAX, NR_PIXBLOCK_PX (&pb), pb.rs); - - nr_pixblock_release (&pb); -} - -void -nr_gdk_draw_gray_garbage (GdkDrawable *drawable, GdkGC *gc, gint x, gint y, gint w, gint h) -{ - for (gint yy = y; yy < y + h; yy += 64) { - for (gint xx = x; xx < x + w; xx += 64) { - NRPixBlock pb; - gint ex = MIN (xx + 64, x + w); - gint ey = MIN (yy + 64, y + h); - nr_pixblock_setup_fast (&pb, NR_PIXBLOCK_MODE_R8G8B8, xx, yy, ex, ey, FALSE); - nr_pixblock_render_gray_noise (&pb, NULL); - gdk_draw_rgb_image (drawable, gc, xx, yy, ex - xx, ey - yy, GDK_RGB_DITHER_NONE, NR_PIXBLOCK_PX (&pb), pb.rs); - nr_pixblock_release (&pb); - } - } -} - diff --git a/src/display/nr-plain-stuff-gdk.h b/src/display/nr-plain-stuff-gdk.h deleted file mode 100644 index bff54a81f..000000000 --- a/src/display/nr-plain-stuff-gdk.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef __NR_PLAIN_STUFF_GDK_H__ -#define __NR_PLAIN_STUFF_GDK_H__ - -/* - * Miscellaneous simple rendering utilities - * - * Author: - * Lauris Kaplinski <lauris@ximian.com> - * - * Copyright (C) 2001 Lauris Kaplinski and Ximian, Inc. - * - * Released under GNU GPL - */ - -#include <gdk/gdk.h> - -void nr_gdk_draw_rgba32_solid (GdkDrawable *drawable, GdkGC *gc, gint x, gint y, gint w, gint h, guint32 rgba); - -void nr_gdk_draw_gray_garbage (GdkDrawable *drawable, GdkGC *gc, gint x, gint y, gint w, gint h); - -#endif - -/* - 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 : diff --git a/src/display/nr-plain-stuff.cpp b/src/display/nr-plain-stuff.cpp deleted file mode 100644 index 62a61102e..000000000 --- a/src/display/nr-plain-stuff.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#define __NR_PLAIN_STUFF_C__ - -/* - * Miscellaneous simple rendering utilities - * - * Author: - * Lauris Kaplinski <lauris@ximian.com> - * - * Copyright (C) 2001 Lauris Kaplinski and Ximian, Inc. - * - * Released under GNU GPL - */ - -#include <glib/gmessages.h> -#include <libnr/nr-pixops.h> -#include "nr-plain-stuff.h" - -#define NR_DEFAULT_CHECKERSIZEP2 2 -#define NR_DEFAULT_CHECKERCOLOR0 0xbfbfbfff -#define NR_DEFAULT_CHECKERCOLOR1 0x808080ff - -void -nr_render_checkerboard_rgb (guchar *px, gint w, gint h, gint rs, gint xoff, gint yoff) -{ - g_return_if_fail (px != NULL); - - nr_render_checkerboard_rgb_custom (px, w, h, rs, xoff, yoff, NR_DEFAULT_CHECKERCOLOR0, NR_DEFAULT_CHECKERCOLOR1, NR_DEFAULT_CHECKERSIZEP2); -} - -void -nr_render_checkerboard_rgb_custom (guchar *px, gint w, gint h, gint rs, gint xoff, gint yoff, guint32 c0, guint32 c1, gint sizep2) -{ - gint x, y, m; - guint r0, g0, b0; - guint r1, g1, b1; - - g_return_if_fail (px != NULL); - g_return_if_fail (sizep2 >= 0); - g_return_if_fail (sizep2 <= 8); - - xoff &= 0x1ff; - yoff &= 0x1ff; - m = 0x1 << sizep2; - r0 = NR_RGBA32_R (c0); - g0 = NR_RGBA32_G (c0); - b0 = NR_RGBA32_B (c0); - r1 = NR_RGBA32_R (c1); - g1 = NR_RGBA32_G (c1); - b1 = NR_RGBA32_B (c1); - - for (y = 0; y < h; y++) { - guchar *p; - p = px; - for (x = 0; x < w; x++) { - if (((x + xoff) ^ (y + yoff)) & m) { - *p++ = r0; - *p++ = g0; - *p++ = b0; - } else { - *p++ = r1; - *p++ = g1; - *p++ = b1; - } - } - px += rs; - } -} - -void -nr_render_rgba32_rgb (guchar *px, gint w, gint h, gint rs, gint xoff, gint yoff, guint32 c) -{ - guint32 c0, c1; - gint a, r, g, b, cr, cg, cb; - - g_return_if_fail (px != NULL); - - r = NR_RGBA32_R (c); - g = NR_RGBA32_G (c); - b = NR_RGBA32_B (c); - a = NR_RGBA32_A (c); - - cr = NR_COMPOSEN11_1111 (r, a, NR_RGBA32_R (NR_DEFAULT_CHECKERCOLOR0)); - cg = NR_COMPOSEN11_1111 (g, a, NR_RGBA32_G (NR_DEFAULT_CHECKERCOLOR0)); - cb = NR_COMPOSEN11_1111 (b, a, NR_RGBA32_B (NR_DEFAULT_CHECKERCOLOR0)); - c0 = (cr << 24) | (cg << 16) | (cb << 8) | 0xff; - - cr = NR_COMPOSEN11_1111 (r, a, NR_RGBA32_R (NR_DEFAULT_CHECKERCOLOR1)); - cg = NR_COMPOSEN11_1111 (g, a, NR_RGBA32_G (NR_DEFAULT_CHECKERCOLOR1)); - cb = NR_COMPOSEN11_1111 (b, a, NR_RGBA32_B (NR_DEFAULT_CHECKERCOLOR1)); - c1 = (cr << 24) | (cg << 16) | (cb << 8) | 0xff; - - nr_render_checkerboard_rgb_custom (px, w, h, rs, xoff, yoff, c0, c1, NR_DEFAULT_CHECKERSIZEP2); -} - diff --git a/src/display/nr-plain-stuff.h b/src/display/nr-plain-stuff.h deleted file mode 100644 index 457442312..000000000 --- a/src/display/nr-plain-stuff.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef __NR_PLAIN_STUFF_H__ -#define __NR_PLAIN_STUFF_H__ - -/* - * Miscellaneous simple rendering utilities - * - * Author: - * Lauris Kaplinski <lauris@ximian.com> - * - * Copyright (C) 2001 Lauris Kaplinski and Ximian, Inc. - * - * Released under GNU GPL - */ - -#include <glib/gtypes.h> - -void nr_render_checkerboard_rgb (guchar *px, gint w, gint h, gint rs, gint xoff, gint yoff); -void nr_render_checkerboard_rgb_custom (guchar *px, gint w, gint h, gint rs, gint xoff, gint yoff, guint32 c0, guint32 c1, gint sizep2); - -void nr_render_rgba32_rgb (guchar *px, gint w, gint h, gint rs, gint xoff, gint yoff, guint32 c); - -#endif - -/* - 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 : diff --git a/src/display/nr-style.cpp b/src/display/nr-style.cpp new file mode 100644 index 000000000..72fa0c444 --- /dev/null +++ b/src/display/nr-style.cpp @@ -0,0 +1,218 @@ +/** + * @file + * @brief Style information for rendering + *//* + * Authors: + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * + * Copyright (C) 2010 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "display/nr-style.h" +#include "style.h" +#include "sp-paint-server.h" +#include "display/canvas-bpath.h" // contains SPStrokeJoinType, SPStrokeCapType etc. (WTF!) + +void NRStyle::Paint::clear() +{ + if (server) { + sp_object_unref(server, NULL); + server = NULL; + } + type = PAINT_NONE; +} + +void NRStyle::Paint::set(SPColor const &c) +{ + clear(); + type = PAINT_COLOR; + color = c; +} + +void NRStyle::Paint::set(SPPaintServer *ps) +{ + clear(); + if (ps) { + type = PAINT_SERVER; + server = ps; + sp_object_ref(server, NULL); + } +} + +NRStyle::NRStyle() + : fill() + , stroke() + , stroke_width(0.0) + , miter_limit(0.0) + , n_dash(0) + , dash(NULL) + , dash_offset(0.0) + , fill_rule(CAIRO_FILL_RULE_EVEN_ODD) + , line_cap(CAIRO_LINE_CAP_BUTT) + , line_join(CAIRO_LINE_JOIN_MITER) + , fill_pattern(NULL) + , stroke_pattern(NULL) +{} + +NRStyle::~NRStyle() +{ + if (fill_pattern) cairo_pattern_destroy(fill_pattern); + if (stroke_pattern) cairo_pattern_destroy(stroke_pattern); + if (dash) delete dash; +} + +void NRStyle::set(SPStyle *style) +{ + if ( style->fill.isPaintserver() ) { + fill.set(style->getFillPaintServer()); + } else if ( style->fill.isColor() ) { + fill.set(style->fill.value.color); + } else if ( style->fill.isNone() ) { + fill.clear(); + } else { + g_assert_not_reached(); + } + fill.opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value); + + switch (style->fill_rule.computed) { + case SP_WIND_RULE_EVENODD: + fill_rule = CAIRO_FILL_RULE_EVEN_ODD; + break; + case SP_WIND_RULE_NONZERO: + fill_rule = CAIRO_FILL_RULE_WINDING; + break; + default: + g_assert_not_reached(); + } + + if ( style->stroke.isPaintserver() ) { + stroke.set(style->getStrokePaintServer()); + } else if ( style->stroke.isColor() ) { + stroke.set(style->stroke.value.color); + } else if ( style->stroke.isNone() ) { + stroke.clear(); + } else { + g_assert_not_reached(); + } + stroke.opacity = SP_SCALE24_TO_FLOAT(style->stroke_opacity.value); + stroke_width = style->stroke_width.computed; + switch (style->stroke_linecap.computed) { + case SP_STROKE_LINECAP_ROUND: + line_cap = CAIRO_LINE_CAP_ROUND; + break; + case SP_STROKE_LINECAP_SQUARE: + line_cap = CAIRO_LINE_CAP_SQUARE; + break; + case SP_STROKE_LINECAP_BUTT: + line_cap = CAIRO_LINE_CAP_BUTT; + break; + default: + g_assert_not_reached(); + } + switch (style->stroke_linejoin.computed) { + case SP_STROKE_LINEJOIN_ROUND: + line_join = CAIRO_LINE_JOIN_ROUND; + break; + case SP_STROKE_LINEJOIN_BEVEL: + line_join = CAIRO_LINE_JOIN_BEVEL; + break; + case SP_STROKE_LINEJOIN_MITER: + line_join = CAIRO_LINE_JOIN_MITER; + break; + default: + g_assert_not_reached(); + } + miter_limit = style->stroke_miterlimit.value; + + if (dash) delete [] dash; + + n_dash = style->stroke_dash.n_dash; + if (n_dash != 0) { + dash_offset = style->stroke_dash.offset; + dash = new double[n_dash]; + for (unsigned int i = 0; i < n_dash; ++i) { + dash[i] = style->stroke_dash.dash[i]; + } + } else { + dash_offset = 0.0; + dash = NULL; + } + + update(); +} + +bool NRStyle::prepareFill(cairo_t *ct, NRRect *paintbox) +{ + // update fill pattern + if (!fill_pattern) { + switch (fill.type) { + case PAINT_SERVER: + fill_pattern = sp_paint_server_create_pattern(fill.server, ct, paintbox, fill.opacity); + break; + case PAINT_COLOR: { + SPColor const &c = fill.color; + fill_pattern = cairo_pattern_create_rgba( + c.v.c[0], c.v.c[1], c.v.c[2], fill.opacity); + } break; + default: break; + } + } + if (!fill_pattern) return false; + return true; +} + +void NRStyle::applyFill(cairo_t *ct) +{ + cairo_set_source(ct, fill_pattern); + cairo_set_fill_rule(ct, fill_rule); +} + +bool NRStyle::prepareStroke(cairo_t *ct, NRRect *paintbox) +{ + if (!stroke_pattern) { + switch (stroke.type) { + case PAINT_SERVER: + stroke_pattern = sp_paint_server_create_pattern(stroke.server, ct, paintbox, stroke.opacity); + break; + case PAINT_COLOR: { + SPColor const &c = stroke.color; + stroke_pattern = cairo_pattern_create_rgba( + c.v.c[0], c.v.c[1], c.v.c[2], stroke.opacity); + } break; + default: break; + } + } + if (!stroke_pattern) return false; + return true; +} + +void NRStyle::applyStroke(cairo_t *ct) +{ + cairo_set_source(ct, stroke_pattern); + cairo_set_line_width(ct, stroke_width); + cairo_set_line_cap(ct, line_cap); + cairo_set_line_join(ct, line_join); + cairo_set_miter_limit(ct, miter_limit); + cairo_set_dash(ct, dash, n_dash, dash_offset); +} + +void NRStyle::update() +{ + // force pattern update + if (fill_pattern) cairo_pattern_destroy(fill_pattern); + if (stroke_pattern) cairo_pattern_destroy(stroke_pattern); + fill_pattern = NULL; + stroke_pattern = NULL; +} + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/display/nr-style.h b/src/display/nr-style.h new file mode 100644 index 000000000..e741e46b4 --- /dev/null +++ b/src/display/nr-style.h @@ -0,0 +1,81 @@ +/** + * @file + * @brief Style information for rendering + *//* + * Authors: + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * + * Copyright (C) 2010 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_NR_ARENA_STYLE_H +#define SEEN_INKSCAPE_DISPLAY_NR_ARENA_STYLE_H + +#include <cairo.h> +#include "color.h" + +class SPColor; +class SPPaintServer; +class SPStyle; +struct NRRect; + +struct NRStyle { + NRStyle(); + ~NRStyle(); + + void set(SPStyle *); + bool prepareFill(cairo_t *ct, NRRect *paintbox); + bool prepareStroke(cairo_t *ct, NRRect *paintbox); + void applyFill(cairo_t *ct); + void applyStroke(cairo_t *ct); + void update(); + + enum PaintType { + PAINT_NONE, + PAINT_COLOR, + PAINT_SERVER + }; + + struct Paint { + Paint() : type(PAINT_NONE), color(0), server(NULL), opacity(1.0) {} + ~Paint() { clear(); } + + PaintType type; + SPColor color; + SPPaintServer *server; + float opacity; + + void clear(); + void set(SPColor const &c); + void set(SPPaintServer *ps); + }; + + Paint fill; + Paint stroke; + float stroke_width; + float miter_limit; + unsigned int n_dash; + double *dash; + float dash_offset; + cairo_fill_rule_t fill_rule; + cairo_line_cap_t line_cap; + cairo_line_join_t line_join; + + cairo_pattern_t *fill_pattern; + cairo_pattern_t *stroke_pattern; +}; + +#endif + + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/display/nr-svgfonts.cpp b/src/display/nr-svgfonts.cpp index cf23ee5d5..8869274d4 100644 --- a/src/display/nr-svgfonts.cpp +++ b/src/display/nr-svgfonts.cpp @@ -14,21 +14,21 @@ #include <2geom/pathvector.h> #include <2geom/transforms.h> -#include "../style.h" #include <cairo.h> #include <vector> +#include "style.h" #include "svg/svg.h" -#include "inkscape-cairo.h" -#include "nr-svgfonts.h" -#include "../sp-path.h" -#include "../sp-object-group.h" -#include "../sp-use.h" -#include "../sp-use-reference.h" -#include "curve.h" +#include "display/cairo-utils.h" +#include "display/nr-svgfonts.h" +#include "display/nr-svgfonts.h" +#include "sp-path.h" +#include "sp-object-group.h" +#include "sp-use.h" +#include "sp-use-reference.h" +#include "display/curve.h" #include "xml/repr.h" #include "sp-font-face.h" - //*************************// // UserFont Implementation // //*************************// diff --git a/src/display/pixblock-scaler.cpp b/src/display/pixblock-scaler.cpp deleted file mode 100644 index 5af5230d8..000000000 --- a/src/display/pixblock-scaler.cpp +++ /dev/null @@ -1,299 +0,0 @@ -#define __NR_PIXBLOCK_SCALER_CPP__ - -/* - * Functions for blitting pixblocks using scaling - * - * Author: - * Niko Kiirala <niko@kiirala.com> - * - * Copyright (C) 2006,2009 Niko Kiirala - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <glib.h> -#include <cmath> -#if defined (SOLARIS) && (SOLARIS == 8) -#include "round.h" -using Inkscape::round; -#endif -using std::floor; - -#include "display/nr-filter-utils.h" -#include "libnr/nr-pixblock.h" -#include "libnr/nr-blit.h" -#include <2geom/forward.h> - -namespace NR { - -struct RGBA { - double r, g, b, a; -}; - -/** Calculates cubically interpolated value of the four given pixel values. - * The pixel values should be from four adjacent pixels in source image or - * four adjacent interpolated values. len should be the x- or y-coordinate - * (depending on interpolation direction) of the center of the target pixel - * in source image coordinates. - */ -__attribute__ ((const)) -inline static double sample(double const a, double const b, - double const c, double const d, - double const len) -{ - double lena = 1.5 + (len - round(len)); - double lenb = 0.5 + (len - round(len)); - double lenc = 0.5 - (len - round(len)); - double lend = 1.5 - (len - round(len)); - double const f = -0.5; // corresponds to cubic Hermite spline - double sum = 0; - sum += ((((f * lena) - 5.0 * f) * lena + 8.0 * f) * lena - 4 * f) * a; - sum += (((f + 2.0) * lenb - (f + 3.0)) * lenb * lenb + 1.0) * b; - sum += (((f + 2.0) * lenc - (f + 3.0)) * lenc * lenc + 1.0) * c; - sum += ((((f * lend) - 5.0 * f) * lend + 8.0 * f) * lend - 4 * f) * d; - - return sum; -} - -/** - * Sanity check function for indexing pixblocks. - * Catches reading and writing outside the pixblock area. - * When enabled, decreases filter rendering speed massively. - */ -inline static void _check_index(NRPixBlock const * const pb, int const location, int const line) -{ - if(false) { - int max_loc = pb->rs * (pb->area.y1 - pb->area.y0); - if (location < 0 || (location + 4) > max_loc) - g_warning("Location %d out of bounds (0 ... %d) at line %d", location, max_loc, line); - } -} - -static void scale_bicubic_rgba(NRPixBlock *to, NRPixBlock *from, - Geom::Affine const &trans) -{ - if (NR_PIXBLOCK_BPP(from) != 4 || NR_PIXBLOCK_BPP(to) != 4) { - g_warning("A non-32-bpp image passed to scale_bicubic_rgba: scaling aborted."); - return; - } - - bool free_from_on_exit = false; - if (from->mode != to->mode){ - NRPixBlock *o_from = from; - from = new NRPixBlock; - nr_pixblock_setup_fast(from, to->mode, o_from->area.x0, o_from->area.y0, o_from->area.x1, o_from->area.y1, false); - nr_blit_pixblock_pixblock(from, o_from); - free_from_on_exit = true; - } - - // 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 = 1.0 / trans[0]; - double from_stepy = 1.0 / trans[3]; - double from_diffx = from_stepx * (-trans[4]); - double from_diffy = from_stepy * (-trans[5]); - from_diffx = (to->area.x0 * from_stepx + from_diffx) - from->area.x0; - from_diffy = (to->area.y0 * from_stepy + from_diffy) - from->area.y0; - - // 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 + 0.5) * from_stepy + from_diffy; - // Pre-calculate beginning of the four horizontal lines, from - // which we should read - int from_line[4]; - for (int i = 0 ; i < 4 ; i++) { - int fy_line = (int)round(from_y) + i - 2; - if (fy_line >= 0) { - if (fy_line < from_height) { - from_line[i] = fy_line * from->rs; - } else { - from_line[i] = (from_height - 1) * from->rs; - } - } else { - 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 + 0.5) * from_stepx + from_diffx; - RGBA line[4]; - for (int i = 0 ; i < 4 ; i++) { - int k = (int)round(from_x) + i - 2; - if (k < 0) k = 0; - if (k >= from_width) k = from_width - 1; - k *= 4; - _check_index(from, from_line[0] + k, __LINE__); - _check_index(from, from_line[1] + k, __LINE__); - _check_index(from, from_line[2] + k, __LINE__); - _check_index(from, from_line[3] + k, __LINE__); - line[i].r = sample(NR_PIXBLOCK_PX(from)[from_line[0] + k], - NR_PIXBLOCK_PX(from)[from_line[1] + k], - NR_PIXBLOCK_PX(from)[from_line[2] + k], - NR_PIXBLOCK_PX(from)[from_line[3] + k], - from_y); - line[i].g = sample(NR_PIXBLOCK_PX(from)[from_line[0] + k + 1], - NR_PIXBLOCK_PX(from)[from_line[1] + k + 1], - NR_PIXBLOCK_PX(from)[from_line[2] + k + 1], - NR_PIXBLOCK_PX(from)[from_line[3] + k + 1], - from_y); - line[i].b = sample(NR_PIXBLOCK_PX(from)[from_line[0] + k + 2], - NR_PIXBLOCK_PX(from)[from_line[1] + k + 2], - NR_PIXBLOCK_PX(from)[from_line[2] + k + 2], - NR_PIXBLOCK_PX(from)[from_line[3] + k + 2], - from_y); - line[i].a = sample(NR_PIXBLOCK_PX(from)[from_line[0] + k + 3], - NR_PIXBLOCK_PX(from)[from_line[1] + k + 3], - NR_PIXBLOCK_PX(from)[from_line[2] + k + 3], - NR_PIXBLOCK_PX(from)[from_line[3] + k + 3], - from_y); - } - RGBA result; - result.r = round(sample(line[0].r, line[1].r, line[2].r, line[3].r, - from_x)); - result.g = round(sample(line[0].g, line[1].g, line[2].g, line[3].g, - from_x)); - result.b = round(sample(line[0].b, line[1].b, line[2].b, line[3].b, - from_x)); - result.a = round(sample(line[0].a, line[1].a, line[2].a, line[3].a, - from_x)); - - _check_index(to, to_y * to->rs + to_x * 4, __LINE__); - - using Inkscape::Filters::clamp; - using Inkscape::Filters::clamp_alpha; - if (to->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) { - /* Clamp the colour channels to range from 0 to result.a to - * make sure, we don't exceed 100% per colour channel with - * images that have premultiplied alpha */ - - int const alpha = clamp((int)result.a); - - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4] - = clamp_alpha((int)result.r, alpha); - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 1] - = clamp_alpha((int)result.g, alpha); - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 2] - = clamp_alpha((int)result.b, alpha); - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 3] = alpha; - } else { - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4] - = clamp((int)result.r); - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 1] - = clamp((int)result.g); - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 2] - = clamp((int)result.b); - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 3] - = clamp((int)result.a); - } - } - } - if (free_from_on_exit) { - nr_pixblock_release(from); - delete from; - } - -} - -void scale_bicubic_alpha(NRPixBlock *to, NRPixBlock *from, - Geom::Affine const &trans) -{ - if (NR_PIXBLOCK_BPP(from) != 1 || NR_PIXBLOCK_BPP(to) != 1) { - g_warning("A non-8-bpp image passed to scale_bicubic_alpha: 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 = 1.0 / trans[0]; - double from_stepy = 1.0 / trans[3]; - double from_diffx = from_stepx * (-trans[4]); - double from_diffy = from_stepy * (-trans[5]); - from_diffx = (to->area.x0 * from_stepx + from_diffx) - from->area.x0; - from_diffy = (to->area.y0 * from_stepy + from_diffy) - from->area.y0; - - // 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 + 0.5) * from_stepy - from_diffy; - // Pre-calculate beginning of the four horizontal lines, from - // which we should read - int from_line[4]; - for (int i = 0 ; i < 4 ; i++) { - int fy_line = (int)round(from_y) + i - 2; - if (fy_line >= 0) { - if (fy_line < from_height) { - from_line[i] = fy_line * from->rs; - } else { - from_line[i] = (from_height - 1) * from->rs; - } - } else { - 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 + 0.5) * from_stepx - from_diffx; - double line[4]; - for (int i = 0 ; i < 4 ; i++) { - int k = (int)round(from_x) + i - 2; - if (k < 0) k = 0; - if (k >= from_width) k = from_width - 1; - _check_index(from, from_line[0] + k, __LINE__); - _check_index(from, from_line[1] + k, __LINE__); - _check_index(from, from_line[2] + k, __LINE__); - _check_index(from, from_line[3] + k, __LINE__); - line[i] = sample(NR_PIXBLOCK_PX(from)[from_line[0] + k], - NR_PIXBLOCK_PX(from)[from_line[1] + k], - NR_PIXBLOCK_PX(from)[from_line[2] + k], - NR_PIXBLOCK_PX(from)[from_line[3] + k], - from_y); - } - int result; - result = (int)round(sample(line[0], line[1], line[2], line[3], - from_x)); - - _check_index(to, to_y * to->rs + to_x, __LINE__); - - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x] - = Inkscape::Filters::clamp(result); - } - } -} - -void scale_bicubic(NRPixBlock *to, NRPixBlock *from, Geom::Affine const &trans) -{ - if (NR_PIXBLOCK_BPP(to) == 4 && NR_PIXBLOCK_BPP(from) == 4) { - scale_bicubic_rgba(to, from, trans); - } else if (NR_PIXBLOCK_BPP(to) == 1 && NR_PIXBLOCK_BPP(from) == 1) { - scale_bicubic_alpha(to, from, trans); - } else { - g_warning("NR::scale_bicubic: unsupported bitdepths for scaling: to %d, from %d", NR_PIXBLOCK_BPP(to), NR_PIXBLOCK_BPP(from)); - } -} - -} /* namespace NR */ -/* - 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 : diff --git a/src/display/pixblock-scaler.h b/src/display/pixblock-scaler.h deleted file mode 100644 index ff9613ab8..000000000 --- a/src/display/pixblock-scaler.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef __NR_PIXBLOCK_SCALER_H__ -#define __NR_PIXBLOCK_SCALER_H__ - -/* - * Functions for blitting pixblocks using scaling - * - * Author: - * Niko Kiirala <niko@kiirala.com> - * - * Copyright (C) 2006 Niko Kiirala - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "libnr/nr-pixblock.h" -#include <2geom/forward.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, Geom::Affine const &trans); - -} /* namespace NR */ - -#endif // __NR_PIXBLOCK_SCALER_H__ -/* - 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 : diff --git a/src/display/pixblock-transform.cpp b/src/display/pixblock-transform.cpp deleted file mode 100644 index 5d5b8a9cf..000000000 --- a/src/display/pixblock-transform.cpp +++ /dev/null @@ -1,279 +0,0 @@ -#define __NR_PIXBLOCK_SCALER_CPP__ - -/* - * Functions for blitting pixblocks using matrix transformation - * - * Author: - * Niko Kiirala <niko@kiirala.com> - * - * Copyright (C) 2006,2009 Niko Kiirala - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <glib.h> -#include <cmath> -#if defined (SOLARIS) && (SOLARIS == 8) -#include "round.h" -using Inkscape::round; -#endif -using std::floor; - -#include "display/nr-filter-utils.h" - -#include "libnr/nr-blit.h" -#include "libnr/nr-pixblock.h" -#include <2geom/affine.h> - -namespace NR { - -struct RGBA { - double r, g, b, a; -}; -struct RGBAi { - int r, g, b, a; -}; - -/** - * Sanity check function for indexing pixblocks. - * Catches reading and writing outside the pixblock area. - * When enabled, decreases filter rendering speed massively. - */ -inline void _check_index(NRPixBlock const * const pb, int const location, int const line) -{ - if(false) { - int max_loc = pb->rs * (pb->area.y1 - pb->area.y0); - if (location < 0 || (location + 4) > max_loc) - g_warning("Location %d out of bounds (0 ... %d) at line %d", location, max_loc, line); - } -} - -void transform_nearest(NRPixBlock *to, NRPixBlock *from, Geom::Affine const &trans) -{ - if (NR_PIXBLOCK_BPP(from) != 4 || NR_PIXBLOCK_BPP(to) != 4) { - g_warning("A non-32-bpp image passed to transform_nearest: scaling aborted."); - return; - } - - bool free_from_on_exit = false; - if (from->mode != to->mode){ - NRPixBlock *o_from = from; - from = new NRPixBlock; - nr_pixblock_setup_fast(from, to->mode, o_from->area.x0, o_from->area.y0, o_from->area.x1, o_from->area.y1, false); - nr_blit_pixblock_pixblock(from, o_from); - free_from_on_exit = true; - } - - // 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; - - Geom::Affine itrans = trans.inverse(); - - // Loop through every pixel of destination image, a line at a time - for (int to_y = 0 ; to_y < to_height ; to_y++) { - for (int to_x = 0 ; to_x < to_width ; to_x++) { - RGBAi result = {0,0,0,0}; - - int from_x = (int)floor(itrans[0] * (to_x + 0.5 + to->area.x0) - + itrans[2] * (to_y + 0.5 + to->area.y0) - + itrans[4]); - from_x -= from->area.x0; - int from_y = (int)floor(itrans[1] * (to_x + 0.5 + to->area.x0) - + itrans[3] * (to_y + 0.5 + to->area.y0) - + itrans[5]); - from_y -= from->area.y0; - - if (from_x >= 0 && from_x < from_width - && from_y >= 0 && from_y < from_height) { - _check_index(from, from_y * from->rs + from_x * 4, __LINE__); - result.r = NR_PIXBLOCK_PX(from)[from_y * from->rs + from_x * 4]; - result.g = NR_PIXBLOCK_PX(from)[from_y * from->rs + from_x * 4 + 1]; - result.b = NR_PIXBLOCK_PX(from)[from_y * from->rs + from_x * 4 + 2]; - result.a = NR_PIXBLOCK_PX(from)[from_y * from->rs + from_x * 4 + 3]; - } - - _check_index(to, to_y * to->rs + to_x * 4, __LINE__); - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4] = result.r; - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 1] = result.g; - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 2] = result.b; - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 3] = result.a; - } - } - if (free_from_on_exit) { - nr_pixblock_release(from); - delete from; - } -} - -/** Calculates cubically interpolated value of the four given pixel values. - * The pixel values should be from four adjacent pixels in source image or - * four adjacent interpolated values. len should be the x- or y-coordinate - * (depending on interpolation direction) of the center of the target pixel - * in source image coordinates. - */ -__attribute__ ((const)) -inline static double sample(double const a, double const b, - double const c, double const d, - double const len) -{ - double lena = 1.5 + (len - round(len)); - double lenb = 0.5 + (len - round(len)); - double lenc = 0.5 - (len - round(len)); - double lend = 1.5 - (len - round(len)); - double const f = -0.5; // corresponds to cubic Hermite spline - double sum = 0; - sum += ((((f * lena) - 5.0 * f) * lena + 8.0 * f) * lena - 4 * f) * a; - sum += (((f + 2.0) * lenb - (f + 3.0)) * lenb * lenb + 1.0) * b; - sum += (((f + 2.0) * lenc - (f + 3.0)) * lenc * lenc + 1.0) * c; - sum += ((((f * lend) - 5.0 * f) * lend + 8.0 * f) * lend - 4 * f) * d; - - return sum; -} - -void transform_bicubic(NRPixBlock *to, NRPixBlock *from, Geom::Affine const &trans) -{ - if (NR_PIXBLOCK_BPP(from) != 4 || NR_PIXBLOCK_BPP(to) != 4) { - g_warning("A non-32-bpp image passed to transform_bicubic: scaling aborted."); - return; - } - - bool free_from_on_exit = false; - if (from->mode != to->mode){ - NRPixBlock *o_from = from; - from = new NRPixBlock; - nr_pixblock_setup_fast(from, to->mode, o_from->area.x0, o_from->area.y0, o_from->area.x1, o_from->area.y1, false); - nr_blit_pixblock_pixblock(from, o_from); - free_from_on_exit = true; - } - - if (from->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) { - // TODO: Fix this... (The problem is that for interpolation non-premultiplied colors should be premultiplied...) - g_warning("transform_bicubic does not properly support non-premultiplied images"); - } - - // 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; - - Geom::Affine itrans = trans.inverse(); - - // Loop through every pixel of destination image, a line at a time - for (int to_y = 0 ; to_y < to_height ; to_y++) { - for (int to_x = 0 ; to_x < to_width ; to_x++) { - double from_x = itrans[0] * (to_x + 0.5 + to->area.x0) - + itrans[2] * (to_y + 0.5 + to->area.y0) - + itrans[4] - from->area.x0; - double from_y = itrans[1] * (to_x + 0.5 + to->area.x0) - + itrans[3] * (to_y + 0.5 + to->area.y0) - + itrans[5] - from->area.y0; - - if (from_x < 0 || from_x >= from_width || - from_y < 0 || from_y >= from_height) { - continue; - } - - RGBA line[4]; - - int from_line[4]; - for (int i = 0 ; i < 4 ; i++) { - int fy_line = (int)round(from_y) + i - 2; - if (fy_line >= 0) { - if (fy_line < from_height) { - from_line[i] = fy_line * from->rs; - } else { - from_line[i] = (from_height - 1) * from->rs; - } - } else { - from_line[i] = 0; - } - } - - for (int i = 0 ; i < 4 ; i++) { - int k = (int)round(from_x) + i - 2; - if (k < 0) k = 0; - if (k >= from_width) k = from_width - 1; - k *= 4; - _check_index(from, from_line[0] + k, __LINE__); - _check_index(from, from_line[1] + k, __LINE__); - _check_index(from, from_line[2] + k, __LINE__); - _check_index(from, from_line[3] + k, __LINE__); - line[i].r = sample(NR_PIXBLOCK_PX(from)[from_line[0] + k], - NR_PIXBLOCK_PX(from)[from_line[1] + k], - NR_PIXBLOCK_PX(from)[from_line[2] + k], - NR_PIXBLOCK_PX(from)[from_line[3] + k], - from_y); - line[i].g = sample(NR_PIXBLOCK_PX(from)[from_line[0] + k + 1], - NR_PIXBLOCK_PX(from)[from_line[1] + k + 1], - NR_PIXBLOCK_PX(from)[from_line[2] + k + 1], - NR_PIXBLOCK_PX(from)[from_line[3] + k + 1], - from_y); - line[i].b = sample(NR_PIXBLOCK_PX(from)[from_line[0] + k + 2], - NR_PIXBLOCK_PX(from)[from_line[1] + k + 2], - NR_PIXBLOCK_PX(from)[from_line[2] + k + 2], - NR_PIXBLOCK_PX(from)[from_line[3] + k + 2], - from_y); - line[i].a = sample(NR_PIXBLOCK_PX(from)[from_line[0] + k + 3], - NR_PIXBLOCK_PX(from)[from_line[1] + k + 3], - NR_PIXBLOCK_PX(from)[from_line[2] + k + 3], - NR_PIXBLOCK_PX(from)[from_line[3] + k + 3], - from_y); - } - RGBA result; - result.r = round(sample(line[0].r, line[1].r, line[2].r, line[3].r, - from_x)); - result.g = round(sample(line[0].g, line[1].g, line[2].g, line[3].g, - from_x)); - result.b = round(sample(line[0].b, line[1].b, line[2].b, line[3].b, - from_x)); - result.a = round(sample(line[0].a, line[1].a, line[2].a, line[3].a, - from_x)); - - using Inkscape::Filters::clamp; - using Inkscape::Filters::clamp_alpha; - _check_index(to, to_y * to->rs + to_x * 4, __LINE__); - if (to->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) { - /* Make sure, none of the RGB channels exceeds 100% intensity - * in premultiplied output */ - int const alpha = clamp((int)result.a); - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4] = - clamp_alpha((int)result.r, alpha); - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 1] = - clamp_alpha((int)result.g, alpha); - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 2] = - clamp_alpha((int)result.b, alpha); - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 3] = alpha; - } else { - /* Clamp the output to unsigned char range */ - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4] - = clamp((int)result.r); - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 1] - = clamp((int)result.g); - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 2] - = clamp((int)result.b); - NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 3] - = clamp((int)result.a); - } - } - } - if (free_from_on_exit) { - nr_pixblock_release(from); - delete from; - } -} - -} /* namespace NR */ -/* - 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 : diff --git a/src/display/pixblock-transform.h b/src/display/pixblock-transform.h deleted file mode 100644 index b73435fdf..000000000 --- a/src/display/pixblock-transform.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef __NR_PIXBLOCK_TRANSFORM_H__ -#define __NR_PIXBLOCK_TRANSFORM_H__ - -/* - * Functions for blitting pixblocks using matrix transfomation - * - * Author: - * Niko Kiirala <niko@kiirala.com> - * - * Copyright (C) 2006 Niko Kiirala - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "libnr/nr-pixblock.h" -#include <2geom/forward.h> - -namespace NR { - -void transform_nearest(NRPixBlock *to, NRPixBlock *from, Geom::Affine const &trans); -void transform_bicubic(NRPixBlock *to, NRPixBlock *from, Geom::Affine const &trans); - -} /* namespace NR */ - -#endif // __NR_PIXBLOCK_TRANSFORM_H__ -/* - 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 : diff --git a/src/display/sodipodi-ctrl.cpp b/src/display/sodipodi-ctrl.cpp index 202fc206e..5e939ffee 100644 --- a/src/display/sodipodi-ctrl.cpp +++ b/src/display/sodipodi-ctrl.cpp @@ -11,7 +11,7 @@ #include <2geom/transforms.h> #include "sp-canvas-util.h" #include "sodipodi-ctrl.h" -#include "libnr/nr-pixops.h" +#include "display/cairo-utils.h" enum { ARG_0, @@ -125,7 +125,7 @@ sp_ctrl_destroy (GtkObject *object) ctrl = SP_CTRL (object); if (ctrl->cache) { - g_free(ctrl->cache); + delete[] ctrl->cache; ctrl->cache = NULL; } @@ -175,11 +175,12 @@ sp_ctrl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) sp_canvas_item_request_update (item); break; - case ARG_FILL_COLOR: - ctrl->fill_color = GTK_VALUE_INT (*arg); + case ARG_FILL_COLOR: { + guint32 fill = GTK_VALUE_INT (*arg); + ctrl->fill_color = fill; ctrl->build = FALSE; sp_canvas_item_request_update (item); - break; + } break; case ARG_STROKED: ctrl->stroked = GTK_VALUE_BOOL (*arg); @@ -187,11 +188,12 @@ sp_ctrl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) sp_canvas_item_request_update (item); break; - case ARG_STROKE_COLOR: - ctrl->stroke_color = GTK_VALUE_INT (*arg); + case ARG_STROKE_COLOR: { + guint32 stroke = GTK_VALUE_INT (*arg); + ctrl->stroke_color = stroke; ctrl->build = FALSE; sp_canvas_item_request_update (item); - break; + } break; case ARG_PIXBUF: pixbuf = (GdkPixbuf*)(GTK_VALUE_POINTER (*arg)); @@ -297,52 +299,56 @@ sp_ctrl_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item) static void sp_ctrl_build_cache (SPCtrl *ctrl) { - guchar * p, *q; + guint32 *p, *q; gint size, x, y, z, s, a, side, c; - guint8 fr, fg, fb, fa, sr, sg, sb, sa; + guint32 stroke_color, fill_color; if (ctrl->filled) { - fr = (ctrl->fill_color >> 24) & 0xff; - fg = (ctrl->fill_color >> 16) & 0xff; - fb = (ctrl->fill_color >> 8) & 0xff; - fa = (ctrl->fill_color) & 0xff; + if (ctrl->mode == SP_CTRL_MODE_XOR) { + fill_color = ctrl->fill_color; + } else { + fill_color = argb32_from_rgba(ctrl->fill_color); + } } else { - fr = 0x00; fg = 0x00; fb = 0x00; fa = 0x00; + fill_color = 0; } if (ctrl->stroked) { - sr = (ctrl->stroke_color >> 24) & 0xff; - sg = (ctrl->stroke_color >> 16) & 0xff; - sb = (ctrl->stroke_color >> 8) & 0xff; - sa = (ctrl->stroke_color) & 0xff; + if (ctrl->mode == SP_CTRL_MODE_XOR) { + stroke_color = ctrl->stroke_color; + } else { + stroke_color = argb32_from_rgba(ctrl->stroke_color); + } } else { - sr = fr; sg = fg; sb = fb; sa = fa; + stroke_color = fill_color; } side = (ctrl->span * 2 +1); - c = ctrl->span ; - size = (side) * (side) * 4; + c = ctrl->span; + size = side * side; if (side < 2) return; - if (ctrl->cache) - g_free (ctrl->cache); - ctrl->cache = (guchar*)g_malloc (size); + if (ctrl->cache) delete[] ctrl->cache; + ctrl->cache = new guint32[size]; switch (ctrl->shape) { case SP_CTRL_SHAPE_SQUARE: p = ctrl->cache; + // top edge for (x=0; x < side; x++) { - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; + *p++ = stroke_color; } + // middle for (y = 2; y < side; y++) { - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; + *p++ = stroke_color; // stroke at first and last pixel for (x=2; x < side; x++) { - *p++ = fr; *p++ = fg; *p++ = fb; *p++ = fa; + *p++ = fill_color; // fill in the middle } - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; + *p++ = stroke_color; } + // bottom edge for (x=0; x < side; x++) { - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; + *p++ = stroke_color; } ctrl->build = TRUE; break; @@ -352,19 +358,20 @@ sp_ctrl_build_cache (SPCtrl *ctrl) for (y = 0; y < side; y++) { z = abs (c - y); for (x = 0; x < z; x++) { - *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; + *p++ = 0; } - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; x++; + *p++ = stroke_color; x++; for (; x < side - z -1; x++) { - *p++ = fr; *p++ = fg; *p++ = fb; *p++ = fa; + *p++ = fill_color; } if (z != c) { - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; x++; + *p++ = stroke_color; x++; } for (; x < side; x++) { - *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; + *p++ = 0; } } + ctrl->build = TRUE; break; case SP_CTRL_SHAPE_CIRCLE: @@ -376,28 +383,28 @@ sp_ctrl_build_cache (SPCtrl *ctrl) z = (gint)(0.0 + sqrt ((c+.4)*(c+.4) - a*a)); x = 0; while (x < c-z) { - *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; - *q-- = 0x00; *q-- = 0x00; *q-- = 0x00; *q-- = 0x00; + *p++ = 0; + *q-- = 0; x++; } do { - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; - *q-- = sa; *q-- = sb; *q-- = sg; *q-- = sr; + *p++ = stroke_color; + *q-- = stroke_color; x++; } while (x < c-s); while (x < MIN(c+s+1, c+z)) { - *p++ = fr; *p++ = fg; *p++ = fb; *p++ = fa; - *q-- = fa; *q-- = fb; *q-- = fg; *q-- = fr; + *p++ = fill_color; + *q-- = fill_color; x++; } do { - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; - *q-- = sa; *q-- = sb; *q-- = sg; *q-- = sr; + *p++ = stroke_color; + *q-- = stroke_color; x++; } while (x <= c+z); while (x < side) { - *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; - *q-- = 0x00; *q-- = 0x00; *q-- = 0x00; *q-- = 0x00; + *p++ = 0; + *q-- = 0; x++; } s = z; @@ -410,17 +417,17 @@ sp_ctrl_build_cache (SPCtrl *ctrl) for (y = 0; y < side; y++) { z = abs (c - y); for (x = 0; x < c-z; x++) { - *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; + *p++ = 0; } - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; x++; + *p++ = stroke_color; x++; for (; x < c + z; x++) { - *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; + *p++ = 0; } if (z != 0) { - *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; x++; + *p++ = stroke_color; x++; } for (; x < side; x++) { - *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; + *p++ = 0; } } ctrl->build = TRUE; @@ -433,28 +440,19 @@ sp_ctrl_build_cache (SPCtrl *ctrl) px = gdk_pixbuf_get_pixels (ctrl->pixbuf); rs = gdk_pixbuf_get_rowstride (ctrl->pixbuf); for (y = 0; y < side; y++){ - unsigned char *s, *d; + guint32 *d; + unsigned char *s; s = px + y * rs; - d = ctrl->cache + 4 * side * y; + d = ctrl->cache + side * y; for (x = 0; x < side; x++) { if (s[3] < 0x80) { - d[0] = 0x00; - d[1] = 0x00; - d[2] = 0x00; - d[3] = 0x00; + *d++ = 0; } else if (s[0] < 0x80) { - d[0] = sr; - d[1] = sg; - d[2] = sb; - d[3] = sa; + *d++ = stroke_color; } else { - d[0] = fr; - d[1] = fg; - d[2] = fb; - d[3] = fa; + *d++ = fill_color; } s += 4; - d += 4; } } } else { @@ -466,16 +464,13 @@ sp_ctrl_build_cache (SPCtrl *ctrl) case SP_CTRL_SHAPE_IMAGE: if (ctrl->pixbuf) { guint r = gdk_pixbuf_get_rowstride (ctrl->pixbuf); - guchar * pix; - q = gdk_pixbuf_get_pixels (ctrl->pixbuf); + guint32 *px; + guchar *data = gdk_pixbuf_get_pixels (ctrl->pixbuf); p = ctrl->cache; for (y = 0; y < side; y++){ - pix = q + (y * r); + px = reinterpret_cast<guint32*>(data + y * r); for (x = 0; x < side; x++) { - *p++ = *pix++; - *p++ = *pix++; - *p++ = *pix++; - *p++ = *pix++; + *p++ = *px++; } } } else { @@ -487,65 +482,84 @@ sp_ctrl_build_cache (SPCtrl *ctrl) default: break; } - } -// composite background, foreground, alpha for xor mode -#define COMPOSE_X(b,f,a) ( FAST_DIVIDE<255>( ((guchar) b) * ((guchar) (0xff - a)) + ((guchar) ((b ^ ~f) + b/4 - (b>127? 63 : 0))) * ((guchar) a) ) ) -// composite background, foreground, alpha for color mode -#define COMPOSE_N(b,f,a) ( FAST_DIVIDE<255>( ((guchar) b) * ((guchar) (0xff - a)) + ((guchar) f) * ((guchar) a) ) ) +static inline guint32 compose_xor(guint32 bg, guint32 fg, guint32 a) +{ + guint32 c = bg * (255-a) + (((bg ^ ~fg) + (bg >> 2) - (bg > 127 ? 63 : 0)) & 255) * a; + return (c + 127) / 255; +} static void sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf) { - gint y0, y1, y, x0,x1,x; - guchar *p, *q, a; + //gint y0, y1, y, x0,x1,x; + //guchar *p, *q, a; SPCtrl *ctrl = SP_CTRL (item); if (!ctrl->defined) return; if ((!ctrl->filled) && (!ctrl->stroked)) return; - sp_canvas_prepare_buffer (buf); - // the control-image is rendered into ctrl->cache if (!ctrl->build) { sp_ctrl_build_cache (ctrl); } - // then we render from ctrl->cache - y0 = MAX (ctrl->box.y0, buf->rect.y0); - y1 = MIN (ctrl->box.y1, buf->rect.y1 - 1); - x0 = MAX (ctrl->box.x0, buf->rect.x0); - x1 = MIN (ctrl->box.x1, buf->rect.x1 - 1); - - bool colormode; - - for (y = y0; y <= y1; y++) { - p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x0 - buf->rect.x0) * 4; - q = ctrl->cache + ((y - ctrl->box.y0) * (ctrl->span*2+1) + (x0 - ctrl->box.x0)) * 4; - for (x = x0; x <= x1; x++) { - a = *(q + 3); - // 00000000 is the only way to get invisible; all other colors with alpha 00 are treated as mode_color with alpha ff - colormode = false; - if (a == 0x00 && !(q[0] == 0x00 && q[1] == 0x00 && q[2] == 0x00)) { - a = 0xff; - colormode = true; - } - if (ctrl->mode == SP_CTRL_MODE_COLOR || colormode) { - p[0] = COMPOSE_N (p[0], q[0], a); - p[1] = COMPOSE_N (p[1], q[1], a); - p[2] = COMPOSE_N (p[2], q[2], a); - q += 4; - p += 4; - } else if (ctrl->mode == SP_CTRL_MODE_XOR) { - p[0] = COMPOSE_X (p[0], q[0], a); - p[1] = COMPOSE_X (p[1], q[1], a); - p[2] = COMPOSE_X (p[2], q[2], a); - q += 4; - p += 4; + int w, h; + w = h = (ctrl->span * 2 +1); + + // The code below works even when the target is not an image surface + if (ctrl->mode == SP_CTRL_MODE_XOR) { + // 1. Copy the affected part of output to a temporary surface + cairo_surface_t *work = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); + cairo_t *cr = cairo_create(work); + cairo_translate(cr, -ctrl->box.x0, -ctrl->box.y0); + cairo_set_source_surface(cr, cairo_get_target(buf->ct), buf->rect.x0, buf->rect.y0); + cairo_paint(cr); + cairo_destroy(cr); + + // 2. Composite the control on a temporary surface + cairo_surface_flush(work); + int strideb = cairo_image_surface_get_stride(work); + unsigned char *pxb = cairo_image_surface_get_data(work); + guint32 *p = ctrl->cache; + for (int i=0; i<h; ++i) { + guint32 *pb = reinterpret_cast<guint32*>(pxb + i*strideb); + for (int j=0; j<w; ++j) { + guint32 cc = *p++; + guint32 ac = cc & 0xff; + if (ac == 0 && cc != 0) { + *pb++ = argb32_from_rgba(cc | 0x000000ff); + } else { + EXTRACT_ARGB32(*pb, ab,rb,gb,bb) + guint32 ro = compose_xor(rb, (cc & 0xff000000) >> 24, ac); + guint32 go = compose_xor(gb, (cc & 0x00ff0000) >> 16, ac); + guint32 bo = compose_xor(bb, (cc & 0x0000ff00) >> 8, ac); + ASSEMBLE_ARGB32(px, ab,ro,go,bo) + *pb++ = px; + } } } + cairo_surface_mark_dirty(work); + + // 3. Replace the affected part of output with contents of temporary surface + cairo_save(buf->ct); + cairo_set_source_surface(buf->ct, work, + ctrl->box.x0 - buf->rect.x0, ctrl->box.y0 - buf->rect.y0); + cairo_rectangle(buf->ct, ctrl->box.x0 - buf->rect.x0, ctrl->box.y0 - buf->rect.y0, w, h); + cairo_clip(buf->ct); + cairo_set_operator(buf->ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(buf->ct); + cairo_restore(buf->ct); + cairo_surface_destroy(work); + } else { + cairo_surface_t *cache = cairo_image_surface_create_for_data( + reinterpret_cast<unsigned char*>(ctrl->cache), CAIRO_FORMAT_ARGB32, w, h, w*4); + cairo_set_source_surface(buf->ct, cache, + ctrl->box.x0 - buf->rect.x0, ctrl->box.y0 - buf->rect.y0); + cairo_paint(buf->ct); + cairo_surface_destroy(cache); } ctrl->shown = TRUE; } diff --git a/src/display/sodipodi-ctrl.h b/src/display/sodipodi-ctrl.h index 71061b450..3bf0889c7 100644 --- a/src/display/sodipodi-ctrl.h +++ b/src/display/sodipodi-ctrl.h @@ -49,7 +49,7 @@ struct SPCtrl : public SPCanvasItem { bool _moved; NRRectL box; /* NB! x1 & y1 are included */ - guchar *cache; + guint32 *cache; GdkPixbuf * pixbuf; void moveto(Geom::Point const p); diff --git a/src/display/sodipodi-ctrlrect.cpp b/src/display/sodipodi-ctrlrect.cpp index 380039798..592d45bc0 100644 --- a/src/display/sodipodi-ctrlrect.cpp +++ b/src/display/sodipodi-ctrlrect.cpp @@ -17,7 +17,7 @@ #include "sp-canvas-util.h" #include "sodipodi-ctrlrect.h" -#include "libnr/nr-pixops.h" +#include "display/cairo-utils.h" /* * Currently we do not have point method, as it should always be painted @@ -83,7 +83,7 @@ static void sp_ctrlrect_destroy(GtkObject *object) (* GTK_OBJECT_CLASS(parent_class)->destroy)(object); } } - +#if 0 /* FIXME: use definitions from somewhere else */ #define RGBA_R(v) ((v) >> 24) #define RGBA_G(v) (((v) >> 16) & 0xff) @@ -153,6 +153,7 @@ static void sp_ctrlrect_area(SPCanvasBuf *buf, gint xs, gint ys, gint xe, gint y } } } +#endif static void sp_ctrlrect_render(SPCanvasItem *item, SPCanvasBuf *buf) { @@ -188,13 +189,38 @@ void CtrlRect::init() void CtrlRect::render(SPCanvasBuf *buf) { + static double const dashes[2] = {4.0, 4.0}; + if ((_area.x0 != 0 || _area.x1 != 0 || _area.y0 != 0 || _area.y1 != 0) && (_area.x0 < buf->rect.x1) && (_area.y0 < buf->rect.y1) && ((_area.x1 + _shadow_size) >= buf->rect.x0) && - ((_area.y1 + _shadow_size) >= buf->rect.y0)) { - sp_canvas_prepare_buffer(buf); + ((_area.y1 + _shadow_size) >= buf->rect.y0)) + { + cairo_save(buf->ct); + cairo_translate(buf->ct, -buf->rect.x0, -buf->rect.y0); + cairo_set_line_width(buf->ct, 1); + if (_dashed) cairo_set_dash(buf->ct, dashes, 2, 0); + cairo_rectangle(buf->ct, 0.5 + _area.x0, 0.5 + _area.y0, + _area.x1 - _area.x0, _area.y1 - _area.y0); + if (_has_fill) { + ink_cairo_set_source_rgba32(buf->ct, _fill_color); + cairo_fill_preserve(buf->ct); + } + ink_cairo_set_source_rgba32(buf->ct, _border_color); + cairo_stroke(buf->ct); + + if (_shadow_size > 0) { + ink_cairo_set_source_rgba32(buf->ct, _shadow_color); + cairo_rectangle(buf->ct, 1 + _area.x1, _area.y0 + _shadow_size, + _shadow_size, _area.y1 - _area.y0 + 1); // right shadow + cairo_rectangle(buf->ct, _area.x0 + _shadow_size, 1 + _area.y1, + _area.x1 - _area.x0 - _shadow_size + 1, _shadow_size); + cairo_fill(buf->ct); + } + cairo_restore(buf->ct); +#if 0 /* Top */ sp_ctrlrect_hline(buf, _area.y0, _area.x0, _area.x1, _border_color, _dashed); /* Bottom */ @@ -216,6 +242,7 @@ void CtrlRect::render(SPCanvasBuf *buf) sp_ctrlrect_area(buf, _area.x0 + 1, _area.y0 + 1, _area.x1 - 1, _area.y1 - 1, _fill_color); } +#endif } } diff --git a/src/display/sp-canvas-util.cpp b/src/display/sp-canvas-util.cpp index 7eac32e2d..186609e49 100644 --- a/src/display/sp-canvas-util.cpp +++ b/src/display/sp-canvas-util.cpp @@ -13,12 +13,10 @@ */ -#include <string.h> // for memset #include <2geom/affine.h> -#include "libnr/nr-pixops.h" -#include "sp-canvas-item.h" #include "sp-canvas-util.h" - +#include "sp-canvas-item.h" +#include "sp-canvas.h" void sp_canvas_update_bbox (SPCanvasItem *item, int x1, int y1, int x2, int y2) @@ -43,38 +41,13 @@ sp_canvas_item_reset_bounds (SPCanvasItem *item) void sp_canvas_prepare_buffer (SPCanvasBuf *buf) { - if (buf->is_empty) { - sp_canvas_clear_buffer(buf); - buf->is_empty = false; - } -} - -void -sp_canvas_clear_buffer (SPCanvasBuf *buf) -{ - unsigned char r, g, b; - - r = (buf->bg_color >> 16) & 0xff; - g = (buf->bg_color >> 8) & 0xff; - b = buf->bg_color & 0xff; - - if ((r != g) || (r != b)) { - int x, y; - for (y = buf->rect.y0; y < buf->rect.y1; y++) { - unsigned char *p; - p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride; - for (x = buf->rect.x0; x < buf->rect.x1; x++) { - *p++ = r; - *p++ = g; - *p++ = b; - } - } - } else { + /*if (buf->is_empty) { int y; for (y = buf->rect.y0; y < buf->rect.y1; y++) { - memset (buf->buf + (y - buf->rect.y0) * buf->buf_rowstride, r, 4 * (buf->rect.x1 - buf->rect.x0)); + memset (buf->buf + (y - buf->rect.y0) * buf->buf_rowstride, 0, 4 * (buf->rect.x1 - buf->rect.x0)); } - } + buf->is_empty = false; + }*/ } Geom::Affine sp_canvas_item_i2p_affine (SPCanvasItem * item) diff --git a/src/display/sp-canvas-util.h b/src/display/sp-canvas-util.h index f0aa15cb9..41e085a5c 100644 --- a/src/display/sp-canvas-util.h +++ b/src/display/sp-canvas-util.h @@ -21,11 +21,6 @@ void sp_canvas_update_bbox (SPCanvasItem *item, int x1, int y1, int x2, int y2); void sp_canvas_item_reset_bounds (SPCanvasItem *item); void sp_canvas_prepare_buffer (SPCanvasBuf *buf); -/* fill buffer with background color */ - -void -sp_canvas_clear_buffer (SPCanvasBuf * buf); - /* get i2p (item to parent) affine transformation as general 6-element array */ Geom::Affine sp_canvas_item_i2p_affine (SPCanvasItem * item); diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index e2220282d..c84452c07 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -15,21 +15,18 @@ */ #ifdef HAVE_CONFIG_H -# include "config.h" +# include <config.h> #endif -#include <libnr/nr-pixblock.h> - #include <gtk/gtk.h> - #include <gtkmm.h> #include "helper/sp-marshal.h" #include <helper/recthull.h> +#include "display-forward.h" +#include <2geom/affine.h> #include "display/sp-canvas.h" #include "display/sp-canvas-group.h" -#include <2geom/affine.h> -#include "libnr/nr-convex-hull.h" #include "preferences.h" #include "inkscape.h" #include "sodipodi-ctrlrect.h" @@ -37,8 +34,7 @@ #include "color-profile-fns.h" #endif // ENABLE_LCMS #include "display/rendermode.h" -#include "libnr/nr-blit.h" -#include "display/inkscape-cairo.h" +#include "display/cairo-utils.h" #include "debug/gdk-event-latency-tracker.h" #include "desktop.h" #include "sp-namedview.h" @@ -315,7 +311,7 @@ sp_canvas_item_invoke_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **a if (SP_CANVAS_ITEM_GET_CLASS (item)->point) return SP_CANVAS_ITEM_GET_CLASS (item)->point (item, p, actual_item); - return NR_HUGE; + return Geom::infinity(); } /** @@ -1629,17 +1625,12 @@ sp_canvas_paint_single_buffer (SPCanvas *canvas, int x0, int y0, int x1, int y1, { GtkWidget *widget = GTK_WIDGET (canvas); - SPCanvasBuf buf; - if (canvas->rendermode != Inkscape::RENDERMODE_OUTLINE) { - buf.buf = nr_pixelstore_256K_new (FALSE, 0); - } else { - buf.buf = nr_pixelstore_1M_new (FALSE, 0); - } - // Mark the region clean sp_canvas_mark_rect(canvas, x0, y0, x1, y1, 0); - buf.buf_rowstride = sw * 4; + SPCanvasBuf buf; + buf.buf = NULL; + buf.buf_rowstride = 0; buf.rect.x0 = x0; buf.rect.y0 = y0; buf.rect.x1 = x1; @@ -1648,114 +1639,75 @@ sp_canvas_paint_single_buffer (SPCanvas *canvas, int x0, int y0, int x1, int y1, buf.visible_rect.y0 = draw_y1; buf.visible_rect.x1 = draw_x2; buf.visible_rect.y1 = draw_y2; - GdkColor *color = &widget->style->bg[GTK_STATE_NORMAL]; - buf.bg_color = (((color->red & 0xff00) << 8) - | (color->green & 0xff00) - | (color->blue >> 8)); buf.is_empty = true; - - buf.ct = nr_create_cairo_context_canvasbuf (&(buf.visible_rect), &buf); + //buf.ct = gdk_cairo_create(widget->window); + + // create temporary surface + int w = x1 - x0; + int h = y1 - y0; + cairo_surface_t *imgs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, x1 - x0, y1 - y0); + buf.ct = cairo_create(imgs); + //cairo_translate(buf.ct, -x0, -y0); + + // fix coordinates, clip all drawing to the tile and clear the background + //cairo_translate(buf.ct, x0 - canvas->x0, y0 - canvas->y0); + //cairo_rectangle(buf.ct, 0, 0, x1 - x0, y1 - y0); + //cairo_set_line_width(buf.ct, 3); + //cairo_set_source_rgba(buf.ct, 1.0, 0.0, 0.0, 0.1); + //cairo_stroke_preserve(buf.ct); + //cairo_clip(buf.ct); + + gdk_cairo_set_source_color(buf.ct, &widget->style->bg[GTK_STATE_NORMAL]); + cairo_set_operator(buf.ct, CAIRO_OPERATOR_SOURCE); + //cairo_rectangle(buf.ct, 0, 0, x1 - x0, y1 - y0); + cairo_paint(buf.ct); + cairo_set_operator(buf.ct, CAIRO_OPERATOR_OVER); if (canvas->root->flags & SP_CANVAS_ITEM_VISIBLE) { SP_CANVAS_ITEM_GET_CLASS (canvas->root)->render (canvas->root, &buf); } -#if ENABLE_LCMS - cmsHTRANSFORM transf = 0; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - bool fromDisplay = prefs->getBool( "/options/displayprofile/from_display"); - if ( fromDisplay ) { - transf = Inkscape::colorprofile_get_display_per( canvas->cms_key ? *(canvas->cms_key) : "" ); - } else { - transf = Inkscape::colorprofile_get_display_transform(); - } -#endif // ENABLE_LCMS + // output to X + cairo_destroy(buf.ct); - if (buf.is_empty) { #if ENABLE_LCMS - if ( transf && canvas->enable_cms_display_adj ) { - cmsDoTransform( transf, &buf.bg_color, &buf.bg_color, 1 ); + if (canvas->enable_cms_display_adj) { + cmsHTRANSFORM transf = 0; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool fromDisplay = prefs->getBool( "/options/displayprofile/from_display"); + if ( fromDisplay ) { + transf = Inkscape::colorprofile_get_display_per( canvas->cms_key ? *(canvas->cms_key) : "" ); + } else { + transf = Inkscape::colorprofile_get_display_transform(); } -#endif // ENABLE_LCMS - gdk_rgb_gc_set_foreground (canvas->pixmap_gc, buf.bg_color); - gdk_draw_rectangle (SP_CANVAS_WINDOW (canvas), - canvas->pixmap_gc, - TRUE, - x0 - canvas->x0, y0 - canvas->y0, - x1 - x0, y1 - y0); - } else { - -#if ENABLE_LCMS - if ( transf && canvas->enable_cms_display_adj ) { - for ( gint yy = 0; yy < (y1 - y0); yy++ ) { - guchar* p = buf.buf + (buf.buf_rowstride * yy); - cmsDoTransform( transf, p, p, (x1 - x0) ); + + if (transf) { + cairo_surface_flush(imgs); + unsigned char *px = cairo_image_surface_get_data(imgs); + int stride = cairo_image_surface_get_stride(imgs); + for (int i=0; i<h; ++i) { + unsigned char *row = px + i*stride; + cmsDoTransform(transf, row, row, w); } + cairo_surface_mark_dirty(imgs); } -#endif // ENABLE_LCMS - -// Now we only need to output the prepared pixmap to the actual screen, and this define chooses one -// of the two ways to do it. The cairo way is direct and straightforward, but unfortunately -// noticeably slower. I asked Carl Worth but he was unable so far to suggest any specific reason -// for this slowness. So, for now we use the oldish method: squeeze out 32bpp buffer to 24bpp and -// use gdk_draw_rgb_image_dithalign, for unfortunately gdk can only handle 24 bpp, which cairo -// cannot handle at all. Still, this way is currently faster even despite the blit with squeeze. - -///#define CANVAS_OUTPUT_VIA_CAIRO - -#ifdef CANVAS_OUTPUT_VIA_CAIRO - - buf.cst = cairo_image_surface_create_for_data ( - buf.buf, - CAIRO_FORMAT_ARGB32, // unpacked, i.e. 32 bits! one byte is unused - x1 - x0, y1 - y0, - buf.buf_rowstride - ); - cairo_t *window_ct = gdk_cairo_create(SP_CANVAS_WINDOW (canvas)); - cairo_set_source_surface (window_ct, buf.cst, x0 - canvas->x0, y0 - canvas->y0); - cairo_paint (window_ct); - cairo_destroy (window_ct); - cairo_surface_finish (buf.cst); - cairo_surface_destroy (buf.cst); - -#else - - NRPixBlock b3; - nr_pixblock_setup_fast (&b3, NR_PIXBLOCK_MODE_R8G8B8, x0, y0, x1, y1, TRUE); - - NRPixBlock b4; - nr_pixblock_setup_extern (&b4, NR_PIXBLOCK_MODE_R8G8B8A8P, x0, y0, x1, y1, - buf.buf, - buf.buf_rowstride, - FALSE, FALSE); - - // this does the 32->24 squishing, using an assembler routine: - nr_blit_pixblock_pixblock (&b3, &b4); - - gdk_draw_rgb_image_dithalign (SP_CANVAS_WINDOW (canvas), - canvas->pixmap_gc, - x0 - canvas->x0, y0 - canvas->y0, - x1 - x0, y1 - y0, - GDK_RGB_DITHER_MAX, - NR_PIXBLOCK_PX(&b3), - sw * 3, - x0 - canvas->x0, y0 - canvas->y0); - - nr_pixblock_release (&b3); - nr_pixblock_release (&b4); -#endif } +#endif // ENABLE_LCMS - cairo_surface_t *cst = cairo_get_target(buf.ct); - cairo_destroy (buf.ct); - cairo_surface_finish (cst); - cairo_surface_destroy (cst); + cairo_t *xct = gdk_cairo_create(widget->window); + cairo_translate(xct, x0 - canvas->x0, y0 - canvas->y0); + cairo_rectangle(xct, 0, 0, x1-x0, y1-y0); + cairo_clip(xct); + cairo_set_source_surface(xct, imgs, 0, 0); + cairo_set_operator(xct, CAIRO_OPERATOR_SOURCE); + cairo_paint(xct); + cairo_destroy(xct); + cairo_surface_destroy(imgs); - if (canvas->rendermode != Inkscape::RENDERMODE_OUTLINE) { - nr_pixelstore_256K_free (buf.buf); - } else { - nr_pixelstore_1M_free (buf.buf); - } + //cairo_surface_t *cst = cairo_get_target(buf.ct); + //cairo_destroy (buf.ct); + //cairo_surface_finish (cst); + //cairo_surface_destroy (cst); } struct PaintRectSetup { @@ -1815,11 +1767,21 @@ sp_canvas_paint_rect_internal (PaintRectSetup const *setup, NRRectL this_rect) if (bw * bh < setup->max_pixels) { // We are small enough + /*GdkRectangle r; + r.x = this_rect.x0 - setup->canvas->x0; + r.y = this_rect.y0 - setup->canvas->y0; + r.width = this_rect.x1 - this_rect.x0; + r.height = this_rect.y1 - this_rect.y0; + + GdkWindow *window = GTK_WIDGET(setup->canvas)->window; + gdk_window_begin_paint_rect(window, &r);*/ + sp_canvas_paint_single_buffer (setup->canvas, this_rect.x0, this_rect.y0, this_rect.x1, this_rect.y1, setup->big_rect.x0, setup->big_rect.y0, setup->big_rect.x1, setup->big_rect.y1, bw); + //gdk_window_end_paint(window); return 1; } diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index e151911dc..7a6b3295e 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -56,18 +56,16 @@ enum { }; /** - * The canvas buf contains the actual pixels. + * Structure used when rendering canvas items. */ -struct SPCanvasBuf{ - guchar *buf; - int buf_rowstride; +struct SPCanvasBuf { + cairo_t *ct; NRRectL rect; NRRectL visible_rect; - /// Background color, given as 0xrrggbb - guint32 bg_color; - // If empty, ignore contents of buffer and use a solid area of bg_color + + unsigned char *buf; + int buf_rowstride; bool is_empty; - cairo_t *ct; }; G_END_DECLS diff --git a/src/display/sp-ctrlline.cpp b/src/display/sp-ctrlline.cpp index ef71c0a16..6c763abdf 100644 --- a/src/display/sp-ctrlline.cpp +++ b/src/display/sp-ctrlline.cpp @@ -19,14 +19,15 @@ * */ -#include "sp-canvas-util.h" -#include "sp-ctrlline.h" - #ifdef HAVE_CONFIG_H # include "config.h" #endif -#include <color.h> -#include "display/inkscape-cairo.h" + +#include "display/sp-ctrlline.h" +#include "display/display-forward.h" +#include "display/sp-canvas-util.h" +#include "display/cairo-utils.h" +#include "color.h" static void sp_ctrlline_class_init (SPCtrlLineClass *klass); @@ -105,11 +106,7 @@ sp_ctrlline_render (SPCanvasItem *item, SPCanvasBuf *buf) if (cl->s == cl->e) return; - sp_canvas_prepare_buffer (buf); - - guint32 rgba = cl->rgba; - cairo_set_source_rgba(buf->ct, SP_RGBA32_B_F(rgba), SP_RGBA32_G_F(rgba), SP_RGBA32_R_F(rgba), SP_RGBA32_A_F(rgba)); - + ink_cairo_set_source_rgba32(buf->ct, cl->rgba); cairo_set_line_width(buf->ct, 1); cairo_new_path(buf->ct); diff --git a/src/display/sp-ctrlpoint.cpp b/src/display/sp-ctrlpoint.cpp index 9f2ecb937..c33cdeeb9 100644 --- a/src/display/sp-ctrlpoint.cpp +++ b/src/display/sp-ctrlpoint.cpp @@ -18,7 +18,7 @@ # include "config.h" #endif #include <color.h> -#include "display/inkscape-cairo.h" +#include "display/cairo-utils.h" static void sp_ctrlpoint_class_init (SPCtrlPointClass *klass); diff --git a/src/display/sp-ctrlquadr.cpp b/src/display/sp-ctrlquadr.cpp index 1ed8d62b8..0701d0b10 100644 --- a/src/display/sp-ctrlquadr.cpp +++ b/src/display/sp-ctrlquadr.cpp @@ -12,10 +12,13 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif -#include "sp-canvas-util.h" + +#include "display-forward.h" #include "sp-canvas-item.h" +#include "sp-canvas.h" +#include "sp-canvas-util.h" #include "sp-ctrlquadr.h" -#include "display/inkscape-cairo.h" +#include "display/cairo-utils.h" #include "color.h" struct SPCtrlQuadr : public SPCanvasItem{ diff --git a/src/display/testnr.cpp b/src/display/testnr.cpp deleted file mode 100644 index 3a3478d28..000000000 --- a/src/display/testnr.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include <gtk/gtk.h> -#include "sp-arena.h" - -int -main (int argc, char ** argv) -{ - GtkWidget * w, * c; - - gtk_init (&argc, &argv); - - w = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - c = sp_arena_new (); - gtk_widget_show (c); - - gtk_container_add (GTK_CONTAINER (w), c); - - gtk_widget_show (w); - - gtk_main (); - - return 0; -} - diff --git a/src/draw-context.cpp b/src/draw-context.cpp index 774fca62d..4dd58afa7 100644 --- a/src/draw-context.cpp +++ b/src/draw-context.cpp @@ -477,6 +477,7 @@ void spdc_endpoint_snap_rotation(SPEventContext const *const ec, Geom::Point &p, { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); unsigned const snaps = abs(prefs->getInt("/options/rotationsnapsperpi/value", 12)); + SnapManager &m = SP_EVENT_CONTEXT_DESKTOP(ec)->namedview->snap_manager; m.setup(SP_EVENT_CONTEXT_DESKTOP(ec)); diff --git a/src/dropper-context.cpp b/src/dropper-context.cpp index a2515c5f0..e30d6b1e8 100644 --- a/src/dropper-context.cpp +++ b/src/dropper-context.cpp @@ -25,6 +25,7 @@ #include "display/canvas-bpath.h" #include "display/canvas-arena.h" #include "display/curve.h" +#include "display/cairo-utils.h" #include "svg/svg-color.h" #include "color.h" #include "color-rgba.h" @@ -40,7 +41,6 @@ #include "dropper-context.h" #include "message-context.h" -//#include "libnr/nr-scale-translate-ops.h" using Inkscape::DocumentUndo; @@ -203,7 +203,7 @@ static gint sp_dropper_context_root_handler(SPEventContext *event_context, GdkEv // otherwise, constantly calculate color no matter is any button pressed or not double rw = 0.0; - double W(0), R(0), G(0), B(0), A(0); + double R(0), G(0), B(0), A(0); if (dc->dragging) { // calculate average @@ -223,56 +223,32 @@ static gint sp_dropper_context_root_handler(SPEventContext *event_context, GdkEv sp_canvas_item_show(dc->area); /* Get buffer */ - const int x0 = (int) floor(dc->centre[Geom::X] - rw); - const int y0 = (int) floor(dc->centre[Geom::Y] - rw); - const int x1 = (int) ceil(dc->centre[Geom::X] + rw); - const int y1 = (int) ceil(dc->centre[Geom::Y] + rw); - - if ((x1 > x0) && (y1 > y0)) { - NRPixBlock pb; - nr_pixblock_setup_fast(&pb, NR_PIXBLOCK_MODE_R8G8B8A8P, x0, y0, x1, y1, TRUE); - /* fixme: (Lauris) */ - sp_canvas_arena_render_pixblock(SP_CANVAS_ARENA(sp_desktop_drawing(desktop)), &pb); - for (int y = y0; y < y1; y++) { - const unsigned char *s = NR_PIXBLOCK_PX(&pb) + (y - y0) * pb.rs; - for (int x = x0; x < x1; x++) { - const double dx = x - dc->centre[Geom::X]; - const double dy = y - dc->centre[Geom::Y]; - const double w = exp(-((dx * dx) + (dy * dy)) / (rw * rw)); - W += w; - R += w * s[0]; - G += w * s[1]; - B += w * s[2]; - A += w * s[3]; - s += 4; - } - } - nr_pixblock_release(&pb); - - R = (R + 0.001) / (255.0 * W); - G = (G + 0.001) / (255.0 * W); - B = (B + 0.001) / (255.0 * W); - A = (A + 0.001) / (255.0 * W); - - R = CLAMP(R, 0.0, 1.0); - G = CLAMP(G, 0.0, 1.0); - B = CLAMP(B, 0.0, 1.0); - A = CLAMP(A, 0.0, 1.0); + Geom::Rect r(dc->centre, dc->centre); + r.expandBy(rw); + if (!r.hasZeroArea()) { + NRRectL area; + area.x0 = r[Geom::X].min(); + area.y0 = r[Geom::Y].min(); + area.x1 = r[Geom::X].max(); + area.y1 = r[Geom::Y].max(); + int w = area.x1 - area.x0; + int h = area.y1 - area.y0; + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); + sp_canvas_arena_render_surface(SP_CANVAS_ARENA(sp_desktop_drawing(desktop)), s, area); + ink_cairo_surface_average_color_premul(s, R, G, B, A); + cairo_surface_destroy(s); } - } else { // pick single pixel - NRPixBlock pb; - int x = (int) floor(event->button.x); - int y = (int) floor(event->button.y); - nr_pixblock_setup_fast(&pb, NR_PIXBLOCK_MODE_R8G8B8A8P, x, y, x+1, y+1, TRUE); - sp_canvas_arena_render_pixblock(SP_CANVAS_ARENA(sp_desktop_drawing(desktop)), &pb); - const unsigned char *s = NR_PIXBLOCK_PX(&pb); - - R = s[0] / 255.0; - G = s[1] / 255.0; - B = s[2] / 255.0; - A = s[3] / 255.0; + NRRectL area; + area.x0 = floor(event->button.x); + area.y0 = floor(event->button.y); + area.x1 = area.x0 + 1; + area.y1 = area.y0 + 1; + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); + sp_canvas_arena_render_surface(SP_CANVAS_ARENA(sp_desktop_drawing(desktop)), s, area); + ink_cairo_surface_average_color_premul(s, R, G, B, A); + cairo_surface_destroy(s); } if (pick == SP_DROPPER_PICK_VISIBLE) { diff --git a/src/dyna-draw-context.cpp b/src/dyna-draw-context.cpp index 2988aea49..aa7d840bc 100644 --- a/src/dyna-draw-context.cpp +++ b/src/dyna-draw-context.cpp @@ -33,6 +33,7 @@ #include "svg/svg.h" #include "display/canvas-bpath.h" +#include "display/cairo-utils.h" #include <2geom/isnan.h> #include <2geom/pathvector.h> #include <2geom/bezier-utils.h> @@ -439,16 +440,16 @@ sp_dyna_draw_brush(SPDynaDrawContext *dc) double trace_thick = 1; if (dc->trace_bg) { // pick single pixel - NRPixBlock pb; - int x = (int) floor(brush_w[Geom::X]); - int y = (int) floor(brush_w[Geom::Y]); - nr_pixblock_setup_fast(&pb, NR_PIXBLOCK_MODE_R8G8B8A8P, x, y, x+1, y+1, TRUE); - sp_canvas_arena_render_pixblock(SP_CANVAS_ARENA(sp_desktop_drawing(SP_EVENT_CONTEXT(dc)->desktop)), &pb); - const unsigned char *s = NR_PIXBLOCK_PX(&pb); - double R = s[0] / 255.0; - double G = s[1] / 255.0; - double B = s[2] / 255.0; - double A = s[3] / 255.0; + double R, G, B, A; + NRRectL area; + area.x0 = floor(brush_w[Geom::X]); + area.y0 = floor(brush_w[Geom::Y]); + area.x1 = area.x0 + 1; + area.y1 = area.y0 + 1; + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); + sp_canvas_arena_render_surface(SP_CANVAS_ARENA(sp_desktop_drawing(SP_EVENT_CONTEXT(dc)->desktop)), s, area); + ink_cairo_surface_average_color_premul(s, R, G, B, A); + cairo_surface_destroy(s); double max = MAX (MAX (R, G), B); double min = MIN (MIN (R, G), B); double L = A * (max + min)/2 + (1 - A); // blend with white bg diff --git a/src/extension/extension.h b/src/extension/extension.h index dba8eeb45..eddddf62c 100644 --- a/src/extension/extension.h +++ b/src/extension/extension.h @@ -51,15 +51,6 @@ #define SP_MODULE_KEY_PRINT_LATEX "org.inkscape.print.latex" /** Defines the key for printing with GNOME Print */ #define SP_MODULE_KEY_PRINT_GNOME "org.inkscape.print.gnome" -/** Defines the key for printing under Win32 */ -#define SP_MODULE_KEY_PRINT_WIN32 "org.inkscape.print.win32" -#ifdef WIN32 -/** Defines the default printing to use */ -#define SP_MODULE_KEY_PRINT_DEFAULT SP_MODULE_KEY_PRINT_WIN32 -#else -/** Defines the default printing to use */ -#define SP_MODULE_KEY_PRINT_DEFAULT SP_MODULE_KEY_PRINT_PS -#endif /** Mime type for SVG */ #define MIME_SVG "image/svg+xml" diff --git a/src/extension/init.cpp b/src/extension/init.cpp index 230d4b50f..355922bc5 100644 --- a/src/extension/init.cpp +++ b/src/extension/init.cpp @@ -26,7 +26,6 @@ #include "db.h" #include "internal/svgz.h" #ifdef WIN32 -# include "internal/win32.h" # include "internal/emf-win32-inout.h" # include "internal/emf-win32-print.h" #endif @@ -171,7 +170,6 @@ init() } #endif #ifdef WIN32 - Internal::PrintWin32::init(); Internal::PrintEmfWin32::init(); Internal::EmfWin32::init(); #endif diff --git a/src/extension/internal/Makefile_insert b/src/extension/internal/Makefile_insert index 3c1ce7f43..36a80712d 100644 --- a/src/extension/internal/Makefile_insert +++ b/src/extension/internal/Makefile_insert @@ -131,8 +131,6 @@ ink_common_sources += \ extension/internal/filter/filter.h \ extension/internal/filter/drop-shadow.h \ extension/internal/filter/snow.h \ - extension/internal/win32.h \ - extension/internal/win32.cpp \ extension/internal/emf-win32-print.h \ extension/internal/emf-win32-print.cpp \ extension/internal/emf-win32-inout.h \ diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index 4eecb5ecc..b9c2a4488 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -37,7 +37,7 @@ #include "display/nr-arena-group.h" #include "display/curve.h" #include "display/canvas-bpath.h" -#include "display/inkscape-cairo.h" +#include "display/cairo-utils.h" #include "sp-item.h" #include "sp-item-group.h" #include "style.h" diff --git a/src/extension/internal/cairo-render-context.h b/src/extension/internal/cairo-render-context.h index d663a82fd..68a3c6537 100644 --- a/src/extension/internal/cairo-render-context.h +++ b/src/extension/internal/cairo-render-context.h @@ -22,6 +22,7 @@ #include <string> #include <2geom/forward.h> +#include <2geom/affine.h> #include "style.h" diff --git a/src/extension/internal/emf-win32-inout.cpp b/src/extension/internal/emf-win32-inout.cpp index 2d97174b1..646b33507 100644 --- a/src/extension/internal/emf-win32-inout.cpp +++ b/src/extension/internal/emf-win32-inout.cpp @@ -31,41 +31,19 @@ #include "sp-root.h" #include "sp-path.h" #include "style.h" -//#include "color.h" -//#include "display/curve.h" -//#include "libnr/nr-point-matrix-ops.h" -//#include "gtk/gtk.h" #include "print.h" -//#include "glibmm/i18n.h" -//#include "extension/extension.h" #include "extension/system.h" #include "extension/print.h" #include "extension/db.h" #include "extension/output.h" -//#include "document.h" #include "display/nr-arena.h" #include "display/nr-arena-item.h" - -//#include "libnr/nr-rect.h" -//#include "libnr/nr-matrix.h" -//#include "libnr/nr-pixblock.h" - -//#include <stdio.h> -//#include <string.h> - -//#include <vector> -//#include <string> - -//#include "io/sys.h" - #include "unit-constants.h" - #include "clear-n_.h" #define WIN32_LEAN_AND_MEAN #include <windows.h> -#include "win32.h" #include "emf-win32-print.h" #include "emf-win32-inout.h" @@ -2321,12 +2299,7 @@ EmfWin32::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) HMETAFILE hmf; HENHMETAFILE hemf; - if (PrintWin32::is_os_wide()) { - fp = CreateFileW(unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - } - else { - fp = CreateFileA(ansi_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - } + fp = CreateFileW(unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if ( fp != INVALID_HANDLE_VALUE ) { filesize = GetFileSize(fp, NULL); @@ -2334,36 +2307,21 @@ EmfWin32::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) } // Try open as Enhanced Metafile - if (PrintWin32::is_os_wide()) - hemf = GetEnhMetaFileW(unicode_uri); - else - hemf = GetEnhMetaFileA(ansi_uri); + hemf = GetEnhMetaFileW(unicode_uri); if (!hemf) { // Try open as Windows Metafile - if (PrintWin32::is_os_wide()) - hmf = GetMetaFileW(unicode_uri); - else - hmf = GetMetaFileA(ansi_uri); + hmf = GetMetaFileW(unicode_uri); METAFILEPICT mp; HDC hDC; if (!hmf) { - if (PrintWin32::is_os_wide()) { - WCHAR szTemp[MAX_PATH]; - - DWORD dw = GetShortPathNameW( unicode_uri, szTemp, MAX_PATH ); - if (dw) { - hmf = GetMetaFileW( szTemp ); - } - } else { - CHAR szTemp[MAX_PATH]; + WCHAR szTemp[MAX_PATH]; - DWORD dw = GetShortPathNameA( ansi_uri, szTemp, MAX_PATH ); - if (dw) { - hmf = GetMetaFileA( szTemp ); - } + DWORD dw = GetShortPathNameW( unicode_uri, szTemp, MAX_PATH ); + if (dw) { + hmf = GetMetaFileW( szTemp ); } } @@ -2410,10 +2368,7 @@ EmfWin32::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) else { // Try open as Aldus Placeable Metafile HANDLE hFile; - if (PrintWin32::is_os_wide()) - hFile = CreateFileW( unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); - else - hFile = CreateFileA( ansi_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + hFile = CreateFileW( unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hFile != INVALID_HANDLE_VALUE) { DWORD nSize = GetFileSize( hFile, NULL ); diff --git a/src/extension/internal/emf-win32-print.cpp b/src/extension/internal/emf-win32-print.cpp index 38db43091..e5d1b0681 100644 --- a/src/extension/internal/emf-win32-print.cpp +++ b/src/extension/internal/emf-win32-print.cpp @@ -56,10 +56,6 @@ //#include "libnrtype/font-instance.h" //#include "libnrtype/font-style-to-pos.h" -#define WIN32_LEAN_AND_MEAN -#include <windows.h> - -#include "win32.h" #include "emf-win32-print.h" #include "unit-constants.h" @@ -185,15 +181,12 @@ PrintEmfWin32::begin (Inkscape::Extension::Print *mod, SPDocument *doc) snprintf(buff+len+1, sizeof(buff)-len-2, "%s", p); // Create the Metafile - if (PrintWin32::is_os_wide()) { + { WCHAR wbuff[1024]; ZeroMemory(wbuff, sizeof(wbuff)); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buff, sizeof(buff)/sizeof(buff[0]), wbuff, sizeof(wbuff)/sizeof(wbuff[0])); hdc = CreateEnhMetaFileW( hScreenDC, unicode_uri, &rc, wbuff ); } - else { - hdc = CreateEnhMetaFileA( hScreenDC, ansi_uri, &rc, buff ); - } // Release the reference DC ReleaseDC( NULL, hScreenDC ); @@ -878,76 +871,40 @@ PrintEmfWin32::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom #endif if (!hfont) { - if (PrintWin32::is_os_wide()) { - LOGFONTW *lf = (LOGFONTW*)g_malloc(sizeof(LOGFONTW)); - g_assert(lf != NULL); - - lf->lfHeight = style->font_size.computed * IN_PER_PX * dwDPI; - lf->lfWidth = 0; - lf->lfEscapement = rot; - lf->lfOrientation = rot; - lf->lfWeight = - style->font_weight.computed == SP_CSS_FONT_WEIGHT_100 ? FW_THIN : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_300 ? FW_LIGHT : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_400 ? FW_NORMAL : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_500 ? FW_MEDIUM : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_600 ? FW_SEMIBOLD : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_700 ? FW_BOLD : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_800 ? FW_EXTRABOLD : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_900 ? FW_HEAVY : - FW_NORMAL; - lf->lfItalic = (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC); - lf->lfUnderline = style->text_decoration.underline; - lf->lfStrikeOut = style->text_decoration.line_through; - lf->lfCharSet = DEFAULT_CHARSET; - lf->lfOutPrecision = OUT_DEFAULT_PRECIS; - lf->lfClipPrecision = CLIP_DEFAULT_PRECIS; - lf->lfQuality = DEFAULT_QUALITY; - lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; - - gunichar2 *unicode_name = g_utf8_to_utf16( style->text->font_family.value, -1, NULL, NULL, NULL ); - wcsncpy(lf->lfFaceName, (wchar_t*) unicode_name, LF_FACESIZE-1); - g_free(unicode_name); - - hfont = CreateFontIndirectW(lf); - - g_free(lf); - } - else { - LOGFONTA *lf = (LOGFONTA*)g_malloc(sizeof(LOGFONTA)); - g_assert(lf != NULL); - - lf->lfHeight = style->font_size.computed * IN_PER_PX * dwDPI; - lf->lfWidth = 0; - lf->lfEscapement = rot; - lf->lfOrientation = rot; - lf->lfWeight = - style->font_weight.computed == SP_CSS_FONT_WEIGHT_100 ? FW_THIN : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_300 ? FW_LIGHT : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_400 ? FW_NORMAL : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_500 ? FW_MEDIUM : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_600 ? FW_SEMIBOLD : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_700 ? FW_BOLD : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_800 ? FW_EXTRABOLD : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_900 ? FW_HEAVY : - FW_NORMAL; - lf->lfItalic = (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC); - lf->lfUnderline = style->text_decoration.underline; - lf->lfStrikeOut = style->text_decoration.line_through; - lf->lfCharSet = DEFAULT_CHARSET; - lf->lfOutPrecision = OUT_DEFAULT_PRECIS; - lf->lfClipPrecision = CLIP_DEFAULT_PRECIS; - lf->lfQuality = DEFAULT_QUALITY; - lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; - - strncpy(lf->lfFaceName, (char*) style->text->font_family.value, LF_FACESIZE-1); - - hfont = CreateFontIndirectA(lf); - - g_free(lf); - } + LOGFONTW *lf = (LOGFONTW*)g_malloc(sizeof(LOGFONTW)); + g_assert(lf != NULL); + + lf->lfHeight = style->font_size.computed * IN_PER_PX * dwDPI; + lf->lfWidth = 0; + lf->lfEscapement = rot; + lf->lfOrientation = rot; + lf->lfWeight = + style->font_weight.computed == SP_CSS_FONT_WEIGHT_100 ? FW_THIN : + style->font_weight.computed == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT : + style->font_weight.computed == SP_CSS_FONT_WEIGHT_300 ? FW_LIGHT : + style->font_weight.computed == SP_CSS_FONT_WEIGHT_400 ? FW_NORMAL : + style->font_weight.computed == SP_CSS_FONT_WEIGHT_500 ? FW_MEDIUM : + style->font_weight.computed == SP_CSS_FONT_WEIGHT_600 ? FW_SEMIBOLD : + style->font_weight.computed == SP_CSS_FONT_WEIGHT_700 ? FW_BOLD : + style->font_weight.computed == SP_CSS_FONT_WEIGHT_800 ? FW_EXTRABOLD : + style->font_weight.computed == SP_CSS_FONT_WEIGHT_900 ? FW_HEAVY : + FW_NORMAL; + lf->lfItalic = (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC); + lf->lfUnderline = style->text_decoration.underline; + lf->lfStrikeOut = style->text_decoration.line_through; + lf->lfCharSet = DEFAULT_CHARSET; + lf->lfOutPrecision = OUT_DEFAULT_PRECIS; + lf->lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf->lfQuality = DEFAULT_QUALITY; + lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + + gunichar2 *unicode_name = g_utf8_to_utf16( style->text->font_family.value, -1, NULL, NULL, NULL ); + wcsncpy(lf->lfFaceName, (wchar_t*) unicode_name, LF_FACESIZE-1); + g_free(unicode_name); + + hfont = CreateFontIndirectW(lf); + + g_free(lf); } HFONT hfontOld = (HFONT) SelectObject(hdc, hfont); @@ -972,13 +929,10 @@ PrintEmfWin32::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom LONG const xpos = (LONG) round(p[Geom::X]); LONG const ypos = (LONG) round(rc.bottom-p[Geom::Y]); - if (PrintWin32::is_os_wide()) { + { gunichar2 *unicode_text = g_utf8_to_utf16( text, -1, NULL, NULL, NULL ); TextOutW(hdc, xpos, ypos, (WCHAR*)unicode_text, wcslen((wchar_t*)unicode_text)); } - else { - TextOutA(hdc, xpos, ypos, (CHAR*)text, strlen((char*)text)); - } SelectObject(hdc, hfontOld); DeleteObject(hfont); diff --git a/src/extension/internal/emf-win32-print.h b/src/extension/internal/emf-win32-print.h index a9f639bcd..44327d35e 100644 --- a/src/extension/internal/emf-win32-print.h +++ b/src/extension/internal/emf-win32-print.h @@ -17,6 +17,9 @@ # include "config.h" #endif +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + #include "extension/implementation/implementation.h" //#include "extension/extension.h" diff --git a/src/extension/internal/win32.cpp b/src/extension/internal/win32.cpp deleted file mode 100644 index 537c91a2c..000000000 --- a/src/extension/internal/win32.cpp +++ /dev/null @@ -1,510 +0,0 @@ -/** @file - * @brief Windows-specific stuff - */ -/* Author: - * Lauris Kaplinski <lauris@kaplinski.com> - * Abhishek Sharma - * - * This code is in public domain - */ - -#ifdef WIN32 - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <glib/gmem.h> -#include <libnr/nr-macros.h> -#include <2geom/transforms.h> - -#include "display/nr-arena-item.h" -#include "display/nr-arena.h" -#include "document.h" - -#include "win32.h" -#include "extension/system.h" -#include "extension/print.h" -#include <gtk/gtk.h> - -/* Initialization */ - -namespace Inkscape { -namespace Extension { -namespace Internal { - -static unsigned int SPWin32Modal = FALSE; - -/** - * Callback function.. not a method - */ -static void -my_gdk_event_handler (GdkEvent *event) -{ - if (SPWin32Modal) { - /* Win32 widget is modal, filter events */ - switch (event->type) { - case GDK_NOTHING: - case GDK_DELETE: - case GDK_SCROLL: - case GDK_BUTTON_PRESS: - case GDK_2BUTTON_PRESS: - case GDK_3BUTTON_PRESS: - case GDK_BUTTON_RELEASE: - case GDK_KEY_PRESS: - case GDK_KEY_RELEASE: - case GDK_DRAG_STATUS: - case GDK_DRAG_ENTER: - case GDK_DRAG_LEAVE: - case GDK_DRAG_MOTION: - case GDK_DROP_START: - case GDK_DROP_FINISHED: - return; - break; - default: - break; - } - } - gtk_main_do_event (event); -} - -void -PrintWin32::main_init (int argc, char **argv, const char *name) -{ - gdk_event_handler_set ((GdkEventFunc) my_gdk_event_handler, NULL, NULL); -} - -void -PrintWin32::finish (void) -{ -} - -#define SP_FOREIGN_MAX_ITER 10 - - -/** - * Callback function.. not a method - */ -static VOID CALLBACK -my_timer (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) -{ - int cdown = 0; - while ((cdown++ < SP_FOREIGN_MAX_ITER) && gdk_events_pending ()) { - gtk_main_iteration_do (FALSE); - } - gtk_main_iteration_do (FALSE); -} - - -/* Platform detection */ - -gboolean -PrintWin32::is_os_wide() -{ - static gboolean initialized = FALSE; - static gboolean is_wide = FALSE; - static OSVERSIONINFOA osver; - - if ( !initialized ) - { - BOOL result; - - initialized = TRUE; - - memset (&osver, 0, sizeof(OSVERSIONINFOA)); - osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); - result = GetVersionExA (&osver); - if (result) - { - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - is_wide = TRUE; - } - // If we can't even call to get the version, fall back to ANSI API - } - - return is_wide; -} - - -/* Printing */ - -PrintWin32::PrintWin32 (void) -{ - /* Nothing here */ -} - - -PrintWin32::~PrintWin32 (void) -{ - DeleteDC (_hDC); -} - - -/** - * Callback function.. not a method - */ -static UINT_PTR CALLBACK -print_hook (HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) -{ -#if 0 - int cdown = 0; - while ((cdown++ < SP_FOREIGN_MAX_ITER) && gdk_events_pending ()) { - gtk_main_iteration_do (FALSE); - } - gtk_main_iteration_do (FALSE); -#endif - return 0; -} - -unsigned int -PrintWin32::setup (Inkscape::Extension::Print *mod) -{ - HRESULT res; - PRINTDLG pd = { - sizeof (PRINTDLG), - NULL, /* hwndOwner */ - NULL, /* hDevMode */ - NULL, /* hDevNames */ - NULL, /* hDC */ - PD_NOPAGENUMS | PD_NOSELECTION | PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE, /* Flags */ - 1, 1, 1, 1, /* nFromPage, nToPage, nMinPage, nMaxPage */ - 1, /* nCoies */ - NULL, /* hInstance */ - 0, /* lCustData */ - NULL, NULL, NULL, NULL, NULL, NULL - }; - UINT_PTR timer; - - SPWin32Modal = TRUE; - pd.Flags |= PD_ENABLEPRINTHOOK; - pd.lpfnPrintHook = print_hook; - timer = SetTimer (NULL, 0, 40, my_timer); - - res = PrintDlg (&pd); - - KillTimer (NULL, timer); - SPWin32Modal = FALSE; - - if (!res) return FALSE; - - _hDC = pd.hDC; - -#if 0 - caps = GetDeviceCaps (_hDC, RASTERCAPS); - if (caps & RC_BANDING) { - printf ("needs banding\n"); - } - if (caps & RC_BITBLT) { - printf ("does bitblt\n"); - } - if (caps & RC_DIBTODEV) { - printf ("does dibtodev\n"); - } - if (caps & RC_STRETCHDIB) { - printf ("does stretchdib\n"); - } -#endif - if (pd.hDevMode) { - DEVMODE *devmodep; - devmodep = (DEVMODE *)pd.hDevMode; - if (devmodep->dmFields & DM_ORIENTATION) { - _landscape = (devmodep->dmOrientation == DMORIENT_LANDSCAPE); - } - } - - return TRUE; -} - -unsigned int -PrintWin32::begin (Inkscape::Extension::Print *mod, SPDocument *doc) -{ - DOCINFO di = { - sizeof (DOCINFO), - NULL, /* lpszDocName */ - NULL, /* lpszOutput */ - NULL, /* lpszDatatype */ - 0 /* DI_APPBANDING */ /* fwType */ - }; - int res; - - _PageWidth = doc->getWidth (); - _PageHeight = doc->getHeight (); - - di.lpszDocName = doc->getName(); - - SPWin32Modal = TRUE; - - res = StartDoc (_hDC, &di); - res = StartPage (_hDC); - - SPWin32Modal = FALSE; - - return 0; -} - -unsigned int -PrintWin32::finish (Inkscape::Extension::Print *mod) -{ - int dpiX, dpiY; - int pPhysicalWidth, pPhysicalHeight; - int pPhysicalOffsetX, pPhysicalOffsetY; - int pPrintableWidth, pPrintableHeight; - float scalex, scaley; - int x0, y0, x1, y1; - int width, height; - unsigned char *px; - int sheight, row; - BITMAPINFO bmInfo = { - { - sizeof (BITMAPINFOHEADER), // bV4Size - 64, // biWidth - 64, // biHeight - 1, // biPlanes - 32, // biBitCount - BI_RGB, // biCompression - 0, // biSizeImage - 2835, // biXPelsPerMeter - 2835, // biYPelsPerMeter - 0, // biClrUsed - 0 // biClrImportant - }, - { { 0, 0, 0, 0 } } // bmiColors - }; - //RECT wrect; - int res; - - SPWin32Modal = TRUE; - - // Number of pixels per logical inch - dpiX = (int) GetDeviceCaps (_hDC, LOGPIXELSX); - dpiY = (int) GetDeviceCaps (_hDC, LOGPIXELSY); - // Size in pixels of the printable area - pPhysicalWidth = GetDeviceCaps (_hDC, PHYSICALWIDTH); - pPhysicalHeight = GetDeviceCaps (_hDC, PHYSICALHEIGHT); - // Top left corner of prontable area - pPhysicalOffsetX = GetDeviceCaps (_hDC, PHYSICALOFFSETX); - pPhysicalOffsetY = GetDeviceCaps (_hDC, PHYSICALOFFSETY); - // Size in pixels of the printable area - pPrintableWidth = GetDeviceCaps (_hDC, HORZRES); - pPrintableHeight = GetDeviceCaps (_hDC, VERTRES); - - // Scaling from document to device - scalex = dpiX / 72.0; - scaley = dpiY / 72.0; - - // We simply map document 0,0 to physical page 0,0 - Geom::Affine affine = Geom::Scale(scalex / 1.25, scaley / 1.25); - - nr_arena_item_set_transform (mod->root, affine); - - // Calculate printable area in device coordinates - x0 = pPhysicalOffsetX; - y0 = pPhysicalOffsetY; - x1 = x0 + pPrintableWidth; - y1 = y0 + pPrintableHeight; - x1 = MIN (x1, (int) (_PageWidth * scalex)); - y1 = MIN (y1, (int) (_PageHeight * scaley)); - - width = x1 - x0; - height = y1 - y0; - - px = g_new (unsigned char, 4 * 64 * width); - sheight = 64; - - /* Printing goes here */ - for (row = 0; row < height; row += 64) { - NRPixBlock pb; - NRRectL bbox; - NRGC gc(NULL); - int num_rows; - int i; - - num_rows = sheight; - if ((row + num_rows) > height) num_rows = height - row; - - /* Set area of interest */ - bbox.x0 = x0; - bbox.y0 = y0 + row; - bbox.x1 = bbox.x0 + width; - bbox.y1 = bbox.y0 + num_rows; - /* Update to renderable state */ - gc.transform.setIdentity(); - nr_arena_item_invoke_update (mod->root, &bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); - - nr_pixblock_setup_extern (&pb, NR_PIXBLOCK_MODE_R8G8B8A8N, bbox.x0, bbox.y0, bbox.x1, bbox.y1, px, 4 * (bbox.x1 - bbox.x0), FALSE, FALSE); - - /* Blitter goes here */ - bmInfo.bmiHeader.biWidth = bbox.x1 - bbox.x0; - bmInfo.bmiHeader.biHeight = -(bbox.y1 - bbox.y0); - - memset (px, 0xff, 4 * num_rows * width); - /* Render */ - nr_arena_item_invoke_render (NULL, mod->root, &bbox, &pb, 0); - - /* Swap red and blue channels; we use RGBA, whereas - * the Win32 GDI uses BGRx. - */ - for ( i = 0 ; i < num_rows * width ; i++ ) { - unsigned char temp=px[i*4]; - px[i*4] = px[i*4+2]; - px[i*4+2] = temp; - } - - SetStretchBltMode(_hDC, COLORONCOLOR); - res = StretchDIBits (_hDC, - bbox.x0 - x0, bbox.y0 - y0, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0, - 0, 0, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0, - px, - &bmInfo, - DIB_RGB_COLORS, - SRCCOPY); - - /* Blitter ends here */ - - nr_pixblock_release (&pb); - } - - g_free (px); - - res = EndPage (_hDC); - res = EndDoc (_hDC); - - SPWin32Modal = FALSE; - - return 0; -} - -/* File dialogs */ - -char * -PrintWin32::get_open_filename (unsigned char *dir, unsigned char *filter, unsigned char *title) -{ - char fnbuf[4096] = {0}; - OPENFILENAME ofn = { - sizeof (OPENFILENAME), - NULL, /* hwndOwner */ - NULL, /* hInstance */ - (const CHAR *)filter, /* lpstrFilter */ - NULL, /* lpstrCustomFilter */ - 0, /* nMaxCustFilter */ - 1, /* nFilterIndex */ - fnbuf, /* lpstrFile */ - sizeof (fnbuf), /* nMaxFile */ - NULL, /* lpstrFileTitle */ - 0, /* nMaxFileTitle */ - (const CHAR *)dir, /* lpstrInitialDir */ - (const CHAR *)title, /* lpstrTitle */ - OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY, /* Flags */ - 0, /* nFileOffset */ - 0, /* nFileExtension */ - NULL, /* lpstrDefExt */ - 0, /* lCustData */ - NULL, /* lpfnHook */ - NULL /* lpTemplateName */ - }; - int retval; - UINT_PTR timer; - - SPWin32Modal = TRUE; - timer = SetTimer (NULL, 0, 40, my_timer); - - retval = GetOpenFileName (&ofn); - - KillTimer (NULL, timer); - SPWin32Modal = FALSE; - - if (!retval) { - int errcode; - errcode = CommDlgExtendedError(); - return NULL; - } - return g_strdup (fnbuf); -} - -char * -PrintWin32::get_write_filename (unsigned char *dir, unsigned char *filter, unsigned char *title) -{ - return NULL; -} - -char * -PrintWin32::get_save_filename (unsigned char *dir, unsigned int *spns) -{ - char fnbuf[4096] = {0}; - OPENFILENAME ofn = { - sizeof (OPENFILENAME), - NULL, /* hwndOwner */ - NULL, /* hInstance */ - "Inkscape SVG (*.svg)\0*\0Plain SVG (*.svg)\0*\0", /* lpstrFilter */ - NULL, /* lpstrCustomFilter */ - 0, /* nMaxCustFilter */ - 1, /* nFilterIndex */ - fnbuf, /* lpstrFile */ - sizeof (fnbuf), /* nMaxFile */ - NULL, /* lpstrFileTitle */ - 0, /* nMaxFileTitle */ - (const CHAR *)dir, /* lpstrInitialDir */ - "Save document to file", /* lpstrTitle */ - OFN_HIDEREADONLY, /* Flags */ - 0, /* nFileOffset */ - 0, /* nFileExtension */ - NULL, /* lpstrDefExt */ - 0, /* lCustData */ - NULL, /* lpfnHook */ - NULL /* lpTemplateName */ - }; - int retval; - UINT_PTR timer; - - SPWin32Modal = TRUE; - timer = SetTimer (NULL, 0, 40, my_timer); - - retval = GetSaveFileName (&ofn); - - KillTimer (NULL, timer); - SPWin32Modal = FALSE; - - if (!retval) { - int errcode; - errcode = CommDlgExtendedError(); - return NULL; - } - *spns = (ofn.nFilterIndex != 2); - return g_strdup (fnbuf); -} - -#include "clear-n_.h" - -void -PrintWin32::init (void) -{ - Inkscape::Extension::Extension * ext; - - /* SVG in */ - ext = Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>" N_("Windows 32-bit Print") "</name>\n" - "<id>" SP_MODULE_KEY_PRINT_WIN32 "</id>\n" - "<param name=\"textToPath\" type=\"boolean\">true</param>\n" - "<print/>\n" - "</inkscape-extension>", new PrintWin32()); - - return; -} - -} /* namespace Internal */ -} /* namespace Extension */ -} /* namespace Inkscape */ - -#endif // ifdef WIN32 - -/* - 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 : diff --git a/src/extension/internal/win32.h b/src/extension/internal/win32.h deleted file mode 100644 index 4a913bb05..000000000 --- a/src/extension/internal/win32.h +++ /dev/null @@ -1,96 +0,0 @@ -/** @file - * @brief Windows-specific stuff - */ -/* Author: - * Lauris Kaplinski <lauris@kaplinski.com> - * Ted Gould <ted@gould.cx> - * - * Lauris: This code is in public domain - * Ted: This code is released under the GNU GPL - */ - -#ifndef __INKSCAPE_EXTENSION_INTERNAL_PRINT_WIN32_H__ -#define __INKSCAPE_EXTENSION_INTERNAL_PRINT_WIN32_H__ -#ifdef WIN32 - -#ifdef HAVE_CONFIG_H - #include <config.h> -#endif - -#ifdef DATADIR -#undef DATADIR -#endif -#include <windows.h> - -#include "extension/extension.h" -#include "extension/implementation/implementation.h" - -namespace Inkscape { -namespace Extension { -namespace Internal { - -/* Initialization */ - -class PrintWin32 : public Inkscape::Extension::Implementation::Implementation { - /* Document dimensions */ - float _PageWidth; - float _PageHeight; - - HDC _hDC; - - unsigned int _landscape; - - void main_init (int argc, char **argv, const char *name); - void finish (void); - - /* File dialogs */ - char *get_open_filename (unsigned char *dir, unsigned char *filter, unsigned char *title); - char *get_write_filename (unsigned char *dir, unsigned char *filter, unsigned char *title); - char *get_save_filename (unsigned char *dir, unsigned int *spns); - - VOID CALLBACK timer (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime); - - -public: - PrintWin32 (void); - virtual ~PrintWin32 (void); - - /* Tell modules about me */ - static void init (void); - - /* Platform detection */ - static gboolean is_os_wide(); - - /* Print functions */ - virtual unsigned int setup (Inkscape::Extension::Print * module); - //virtual unsigned int set_preview (Inkscape::Extension::Print * module); - - virtual unsigned int begin (Inkscape::Extension::Print * module, SPDocument *doc); - virtual unsigned int finish (Inkscape::Extension::Print * module); - - /* Rendering methods */ - /* - virtual unsigned int bind (Inkscape::Extension::Print * module, const Geom::Affine *transform, float opacity); - virtual unsigned int release (Inkscape::Extension::Print * module); - virtual unsigned int comment (Inkscape::Extension::Print * module, const char * comment); - virtual unsigned int image (Inkscape::Extension::Print * module, unsigned char *px, unsigned int w, unsigned int h, unsigned int rs, - const Geom::Affine *transform, const SPStyle *style); - */ -}; - -} /* namespace Internal */ -} /* namespace Extension */ -} /* namespace Inkscape */ - -#endif // ifdef WIN32 -#endif /* __INKSCAPE_EXTENSION_INTERNAL_PRINT_WIN32_H__ */ -/* - 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 : diff --git a/src/file.cpp b/src/file.cpp index 2e7e74610..43d1ddaaa 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -31,7 +31,6 @@ #include <gtk/gtk.h> #include <glib/gmem.h> #include <glibmm/i18n.h> -#include <libnr/nr-pixops.h> #include "desktop.h" #include "desktop-handles.h" @@ -1523,20 +1522,6 @@ sp_file_print(Gtk::Window& parentWindow) sp_print_document(parentWindow, doc); } -/** - * Display what the drawing would look like, if - * printed. - */ -void -sp_file_print_preview(gpointer /*object*/, gpointer /*data*/) -{ - - SPDocument *doc = SP_ACTIVE_DOCUMENT; - if (doc) - sp_print_preview_document(doc); - -} - /* Local Variables: diff --git a/src/file.h b/src/file.h index dec7e3f14..0041af81f 100644 --- a/src/file.h +++ b/src/file.h @@ -183,11 +183,6 @@ would be useful as instance methods */ void sp_file_print (Gtk::Window& parentWindow); -/** - * - */ -void sp_file_print_preview (gpointer object, gpointer data); - /*##################### ## U T I L I T Y #####################*/ diff --git a/src/filter-chemistry.cpp b/src/filter-chemistry.cpp index 18a31f0d7..b78b96c02 100644 --- a/src/filter-chemistry.cpp +++ b/src/filter-chemistry.cpp @@ -22,11 +22,10 @@ #include "filter-enums.h" #include "filters/blend.h" +#include "filters/gaussian-blur.h" #include "sp-filter.h" #include "sp-filter-reference.h" -#include "sp-gaussian-blur.h" #include "svg/css-ostringstream.h" -#include "libnr/nr-matrix-fns.h" #include "xml/repr.h" diff --git a/src/filter-chemistry.h b/src/filter-chemistry.h index 9e97d6f80..9f16419fd 100644 --- a/src/filter-chemistry.h +++ b/src/filter-chemistry.h @@ -1,6 +1,3 @@ -#ifndef __SP_FILTER_CHEMISTRY_H__ -#define __SP_FILTER_CHEMISTRY_H__ - /* * Various utility methods for filters * @@ -14,8 +11,14 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifndef SEEN_SP_FILTER_CHEMISTRY_H +#define SEEN_SP_FILTER_CHEMISTRY_H + #include "forward.h" -#include "sp-filter.h" +#include "display/nr-filter-types.h" + +class SPFilter; +class SPFilterPrimitive; SPFilterPrimitive *filter_add_primitive(SPFilter *filter, Inkscape::Filters::FilterPrimitiveType); SPFilter *new_filter (SPDocument *document); diff --git a/src/filters/Makefile_insert b/src/filters/Makefile_insert index dde7cdb68..ea9ff4b56 100644 --- a/src/filters/Makefile_insert +++ b/src/filters/Makefile_insert @@ -1,59 +1,46 @@ ## Makefile.am fragment sourced by src/Makefile.am. ink_common_sources += \ - filters/blend.cpp \ - filters/blend-fns.h \ - filters/blend.h \ - filters/colormatrix.cpp \ - filters/colormatrix-fns.h \ - filters/colormatrix.h \ - filters/componenttransfer.cpp \ - filters/componenttransfer-fns.h \ + filters/blend.cpp \ + filters/blend.h \ + filters/colormatrix.cpp \ + filters/colormatrix.h \ + filters/componenttransfer.cpp \ filters/componenttransfer-funcnode.cpp \ filters/componenttransfer-funcnode.h \ - filters/componenttransfer.h \ - filters/composite.cpp \ - filters/composite-fns.h \ - filters/composite.h \ - filters/convolvematrix.cpp \ - filters/convolvematrix-fns.h \ - filters/convolvematrix.h \ - filters/diffuselighting.cpp \ - filters/diffuselighting-fns.h \ - filters/diffuselighting.h \ - filters/displacementmap.cpp \ - filters/displacementmap-fns.h \ - filters/displacementmap.h \ - filters/distantlight.cpp \ - filters/distantlight.h \ - filters/flood.cpp \ - filters/flood-fns.h \ - filters/flood.h \ - filters/image.cpp \ - filters/image-fns.h \ - filters/image.h \ - filters/merge.cpp \ - filters/merge-fns.h \ - filters/merge.h \ - filters/mergenode.cpp \ - filters/mergenode.h \ - filters/morphology.cpp \ - filters/morphology-fns.h \ - filters/morphology.h \ - filters/offset.cpp \ - filters/offset-fns.h \ - filters/offset.h \ - filters/pointlight.cpp \ - filters/pointlight.h \ - filters/specularlighting.cpp \ - filters/specularlighting-fns.h \ - filters/specularlighting.h \ - filters/spotlight.cpp \ - filters/spotlight.h \ - filters/tile.cpp \ - filters/tile-fns.h \ - filters/tile.h \ - filters/turbulence.cpp \ - filters/turbulence-fns.h \ + filters/componenttransfer.h \ + filters/composite.cpp \ + filters/composite.h \ + filters/convolvematrix.cpp \ + filters/convolvematrix.h \ + filters/diffuselighting.cpp \ + filters/diffuselighting.h \ + filters/displacementmap.cpp \ + filters/displacementmap.h \ + filters/distantlight.cpp \ + filters/distantlight.h \ + filters/flood.cpp \ + filters/flood.h \ + filters/gaussian-blur.cpp \ + filters/gaussian-blur.h \ + filters/image.cpp \ + filters/image.h \ + filters/merge.cpp \ + filters/merge.h \ + filters/mergenode.cpp \ + filters/mergenode.h \ + filters/morphology.cpp \ + filters/morphology.h \ + filters/offset.cpp \ + filters/offset.h \ + filters/pointlight.cpp \ + filters/pointlight.h \ + filters/specularlighting.cpp \ + filters/specularlighting.h \ + filters/spotlight.cpp \ + filters/spotlight.h \ + filters/tile.cpp \ + filters/tile.h \ + filters/turbulence.cpp \ filters/turbulence.h diff --git a/src/filters/blend-fns.h b/src/filters/blend-fns.h deleted file mode 100644 index 94456e0dd..000000000 --- a/src/filters/blend-fns.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef SP_FEBLEND_FNS_H -#define SP_FEBLEND_FNS_H - -/** \file - * Macros and fn declarations related to gaussian blur filter. - */ - -#include <glib-object.h> -#include <glib/gtypes.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -class SPFeBlend; - -#define SP_TYPE_FEBLEND (sp_feBlend_get_type()) -#define SP_FEBLEND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEBLEND, SPFeBlend)) -#define SP_FEBLEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEBLEND, SPFeBlendClass)) -#define SP_IS_FEBLEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEBLEND)) -#define SP_IS_FEBLEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEBLEND)) - -GType sp_feBlend_get_type(); - -#endif /* !SP_FEBLEND_FNS_H */ - -/* - 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 : diff --git a/src/filters/blend.cpp b/src/filters/blend.cpp index 9a52d86f7..809bd6c00 100644 --- a/src/filters/blend.cpp +++ b/src/filters/blend.cpp @@ -19,9 +19,10 @@ #include <string.h> +#include "sp-filter.h" +#include "filters/blend.h" #include "attributes.h" #include "svg/svg.h" -#include "blend.h" #include "xml/repr.h" #include "display/nr-filter.h" diff --git a/src/filters/blend.h b/src/filters/blend.h index 62c6faaee..e7fc410e7 100644 --- a/src/filters/blend.h +++ b/src/filters/blend.h @@ -1,10 +1,6 @@ -#ifndef SP_FEBLEND_H_SEEN -#define SP_FEBLEND_H_SEEN - -/** \file - * SVG <feBlend> implementation, see Blend.cpp. - */ -/* +/** @file + * @brief SVG blend filter effect + *//* * Authors: * Hugo Rodrigues <haa.rodrigues@gmail.com> * Niko Kiirala <niko@kiirala.com> @@ -14,16 +10,21 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "sp-filter.h" -#include "blend-fns.h" +#ifndef SP_FEBLEND_H_SEEN +#define SP_FEBLEND_H_SEEN +#include "sp-filter-primitive.h" #include "display/nr-filter-blend.h" -/* FeBlend base class */ +#define SP_TYPE_FEBLEND (sp_feBlend_get_type()) +#define SP_FEBLEND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEBLEND, SPFeBlend)) +#define SP_FEBLEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEBLEND, SPFeBlendClass)) +#define SP_IS_FEBLEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEBLEND)) +#define SP_IS_FEBLEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEBLEND)) + class SPFeBlendClass; struct SPFeBlend : public SPFilterPrimitive { - /** BLEND ATTRIBUTES HERE */ Inkscape::Filters::FilterBlendMode blend_mode; int in2; }; diff --git a/src/filters/colormatrix-fns.h b/src/filters/colormatrix-fns.h deleted file mode 100644 index 62f7a190d..000000000 --- a/src/filters/colormatrix-fns.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef SP_FECOLORMATRIX_FNS_H -#define SP_FECOLORMATRIX_FNS_H - -/** \file - * Macros and fn declarations related to gaussian blur filter. - */ - -#include <glib-object.h> -#include <glib/gtypes.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -class SPFeColorMatrix; - -#define SP_TYPE_FECOLORMATRIX (sp_feColorMatrix_get_type()) -#define SP_FECOLORMATRIX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FECOLORMATRIX, SPFeColorMatrix)) -#define SP_FECOLORMATRIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FECOLORMATRIX, SPFeColorMatrixClass)) -#define SP_IS_FECOLORMATRIX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FECOLORMATRIX)) -#define SP_IS_FECOLORMATRIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FECOLORMATRIX)) - -GType sp_feColorMatrix_get_type(); - -#endif /* !SP_FECOLORMATRIX_FNS_H */ - -/* - 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 : diff --git a/src/filters/colormatrix.cpp b/src/filters/colormatrix.cpp index 34e730c65..b110e2766 100644 --- a/src/filters/colormatrix.cpp +++ b/src/filters/colormatrix.cpp @@ -26,6 +26,7 @@ #include "xml/repr.h" #include "helper-fns.h" +#include "display/nr-filter.h" #include "display/nr-filter-colormatrix.h" /* FeColorMatrix base class */ diff --git a/src/filters/colormatrix.h b/src/filters/colormatrix.h index 754607608..8eb750ac1 100644 --- a/src/filters/colormatrix.h +++ b/src/filters/colormatrix.h @@ -1,10 +1,6 @@ -#ifndef SP_FECOLORMATRIX_H_SEEN -#define SP_FECOLORMATRIX_H_SEEN - -/** \file - * SVG <feColorMatrix> implementation, see ColorMatrix.cpp. - */ -/* +/** @file + * @brief SVG color matrix filter effect + *//* * Authors: * Hugo Rodrigues <haa.rodrigues@gmail.com> * @@ -12,17 +8,22 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifndef SP_FECOLORMATRIX_H_SEEN +#define SP_FECOLORMATRIX_H_SEEN -#include "sp-filter.h" -#include "colormatrix-fns.h" -#include "display/nr-filter-colormatrix.h" #include <vector> +#include "sp-filter-primitive.h" +#include "display/nr-filter-colormatrix.h" + +#define SP_TYPE_FECOLORMATRIX (sp_feColorMatrix_get_type()) +#define SP_FECOLORMATRIX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FECOLORMATRIX, SPFeColorMatrix)) +#define SP_FECOLORMATRIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FECOLORMATRIX, SPFeColorMatrixClass)) +#define SP_IS_FECOLORMATRIX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FECOLORMATRIX)) +#define SP_IS_FECOLORMATRIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FECOLORMATRIX)) -/* FeColorMatrix base class */ class SPFeColorMatrixClass; struct SPFeColorMatrix : public SPFilterPrimitive { - /** COLORMATRIX ATTRIBUTES HERE */ Inkscape::Filters::FilterColorMatrixType type; gdouble value; std::vector<gdouble> values; @@ -34,7 +35,6 @@ struct SPFeColorMatrixClass { GType sp_feColorMatrix_get_type(); - #endif /* !SP_FECOLORMATRIX_H_SEEN */ /* diff --git a/src/filters/componenttransfer-fns.h b/src/filters/componenttransfer-fns.h deleted file mode 100644 index 65120fefa..000000000 --- a/src/filters/componenttransfer-fns.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef SP_FECOMPONENTTRANSFER_FNS_H -#define SP_FECOMPONENTTRANSFER_FNS_H - -/** \file - * Macros and fn declarations related to gaussian blur filter. - */ - -#include <glib-object.h> -#include <glib/gtypes.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -class SPFeComponentTransfer; - -#define SP_TYPE_FECOMPONENTTRANSFER (sp_feComponentTransfer_get_type()) -#define SP_FECOMPONENTTRANSFER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FECOMPONENTTRANSFER, SPFeComponentTransfer)) -#define SP_FECOMPONENTTRANSFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FECOMPONENTTRANSFER, SPFeComponentTransferClass)) -#define SP_IS_FECOMPONENTTRANSFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FECOMPONENTTRANSFER)) -#define SP_IS_FECOMPONENTTRANSFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FECOMPONENTTRANSFER)) - -GType sp_feComponentTransfer_get_type(); - -#endif /* !SP_FECOMPONENTTRANSFER_FNS_H */ - -/* - 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 : diff --git a/src/filters/componenttransfer.cpp b/src/filters/componenttransfer.cpp index 48d9c3212..99d8616f4 100644 --- a/src/filters/componenttransfer.cpp +++ b/src/filters/componenttransfer.cpp @@ -21,9 +21,10 @@ #include "document.h" #include "attributes.h" #include "svg/svg.h" -#include "componenttransfer.h" -#include "componenttransfer-funcnode.h" +#include "filters/componenttransfer.h" +#include "filters/componenttransfer-funcnode.h" #include "xml/repr.h" +#include "display/nr-filter.h" #include "display/nr-filter-component-transfer.h" /* FeComponentTransfer base class */ diff --git a/src/filters/componenttransfer.h b/src/filters/componenttransfer.h index 8a9c3c682..2df64009f 100644 --- a/src/filters/componenttransfer.h +++ b/src/filters/componenttransfer.h @@ -1,10 +1,6 @@ -#ifndef SP_FECOMPONENTTRANSFER_H_SEEN -#define SP_FECOMPONENTTRANSFER_H_SEEN - -/** \file - * SVG <feComponentTransfer> implementation, see ComponentTransfer.cpp. - */ -/* +/** @file + * @brief SVG component transferfilter effect + *//* * Authors: * Hugo Rodrigues <haa.rodrigues@gmail.com> * @@ -12,18 +8,25 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifndef SP_FECOMPONENTTRANSFER_H_SEEN +#define SP_FECOMPONENTTRANSFER_H_SEEN + +#include "sp-filter-primitive.h" -#include "sp-filter.h" -#include "componenttransfer-fns.h" -#include "display/nr-filter-component-transfer.h" -#include <vector> +#define SP_TYPE_FECOMPONENTTRANSFER (sp_feComponentTransfer_get_type()) +#define SP_FECOMPONENTTRANSFER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FECOMPONENTTRANSFER, SPFeComponentTransfer)) +#define SP_FECOMPONENTTRANSFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FECOMPONENTTRANSFER, SPFeComponentTransferClass)) +#define SP_IS_FECOMPONENTTRANSFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FECOMPONENTTRANSFER)) +#define SP_IS_FECOMPONENTTRANSFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FECOMPONENTTRANSFER)) + +namespace Inkscape { +namespace Filters { +class FilterComponentTransfer; +} } -/* FeComponentTransfer base class */ class SPFeComponentTransferClass; struct SPFeComponentTransfer : public SPFilterPrimitive { - /** COMPONENTTRANSFER ATTRIBUTES HERE */ - Inkscape::Filters::FilterComponentTransfer *renderer; }; diff --git a/src/filters/composite-fns.h b/src/filters/composite-fns.h deleted file mode 100644 index 04530b152..000000000 --- a/src/filters/composite-fns.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef SP_FECOMPOSITE_FNS_H -#define SP_FECOMPOSITE_FNS_H - -/** \file - * Macros and fn declarations related to gaussian blur filter. - */ - -#include <glib-object.h> -#include <glib/gtypes.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -class SPFeComposite; - -#define SP_TYPE_FECOMPOSITE (sp_feComposite_get_type()) -#define SP_FECOMPOSITE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FECOMPOSITE, SPFeComposite)) -#define SP_FECOMPOSITE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FECOMPOSITE, SPFeCompositeClass)) -#define SP_IS_FECOMPOSITE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FECOMPOSITE)) -#define SP_IS_FECOMPOSITE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FECOMPOSITE)) - -GType sp_feComposite_get_type(); - -#endif /* !SP_FECOMPOSITE_FNS_H */ - -/* - 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 : diff --git a/src/filters/composite.cpp b/src/filters/composite.cpp index c2b47c4c2..66e8e3415 100644 --- a/src/filters/composite.cpp +++ b/src/filters/composite.cpp @@ -18,10 +18,12 @@ #include "attributes.h" #include "svg/svg.h" -#include "composite.h" +#include "filters/composite.h" #include "helper-fns.h" #include "xml/repr.h" +#include "display/nr-filter.h" #include "display/nr-filter-composite.h" +#include "sp-filter.h" /* FeComposite base class */ diff --git a/src/filters/composite.h b/src/filters/composite.h index 0fa1b5665..3eb62716f 100644 --- a/src/filters/composite.h +++ b/src/filters/composite.h @@ -1,10 +1,6 @@ -#ifndef SP_FECOMPOSITE_H_SEEN -#define SP_FECOMPOSITE_H_SEEN - -/** \file - * SVG <feComposite> implementation, see Composite.cpp. - */ -/* +/** @file + * @brief SVG composite filter effect + *//* * Authors: * Hugo Rodrigues <haa.rodrigues@gmail.com> * @@ -12,9 +8,16 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifndef SP_FECOMPOSITE_H_SEEN +#define SP_FECOMPOSITE_H_SEEN -#include "sp-filter.h" -#include "composite-fns.h" +#include "sp-filter-primitive.h" + +#define SP_TYPE_FECOMPOSITE (sp_feComposite_get_type()) +#define SP_FECOMPOSITE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FECOMPOSITE, SPFeComposite)) +#define SP_FECOMPOSITE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FECOMPOSITE, SPFeCompositeClass)) +#define SP_IS_FECOMPOSITE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FECOMPOSITE)) +#define SP_IS_FECOMPOSITE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FECOMPOSITE)) enum FeCompositeOperator { // Default value is 'over', but let's distinquish specifying the @@ -29,7 +32,6 @@ enum FeCompositeOperator { COMPOSITE_ENDOPERATOR }; -/* FeComposite base class */ class SPFeCompositeClass; struct SPFeComposite : public SPFilterPrimitive { @@ -44,7 +46,6 @@ struct SPFeCompositeClass { GType sp_feComposite_get_type(); - #endif /* !SP_FECOMPOSITE_H_SEEN */ /* diff --git a/src/filters/convolvematrix-fns.h b/src/filters/convolvematrix-fns.h deleted file mode 100644 index f6a4c846a..000000000 --- a/src/filters/convolvematrix-fns.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef SP_FECONVOLVEMATRIX_FNS_H -#define SP_FECONVOLVEMATRIX_FNS_H - -/** \file - * Macros and fn declarations related to gaussian blur filter. - */ - -#include <glib-object.h> -#include <glib/gtypes.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -class SPFeConvolveMatrix; - -#define SP_TYPE_FECONVOLVEMATRIX (sp_feConvolveMatrix_get_type()) -#define SP_FECONVOLVEMATRIX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FECONVOLVEMATRIX, SPFeConvolveMatrix)) -#define SP_FECONVOLVEMATRIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FECONVOLVEMATRIX, SPFeConvolveMatrixClass)) -#define SP_IS_FECONVOLVEMATRIX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FECONVOLVEMATRIX)) -#define SP_IS_FECONVOLVEMATRIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FECONVOLVEMATRIX)) - -GType sp_feConvolveMatrix_get_type(); - -#endif /* !SP_FECONVOLVEMATRIX_FNS_H */ - -/* - 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 : diff --git a/src/filters/convolvematrix.cpp b/src/filters/convolvematrix.cpp index 99c6ca413..20d652bee 100644 --- a/src/filters/convolvematrix.cpp +++ b/src/filters/convolvematrix.cpp @@ -18,15 +18,15 @@ #endif #include <string.h> - +#include <math.h> #include <vector> #include "attributes.h" #include "svg/svg.h" -#include "convolvematrix.h" +#include "filters/convolvematrix.h" #include "helper-fns.h" #include "xml/repr.h" +#include "display/nr-filter.h" #include "display/nr-filter-convolve-matrix.h" -#include <math.h> /* FeConvolveMatrix base class */ diff --git a/src/filters/convolvematrix.h b/src/filters/convolvematrix.h index 1d085fd6c..4c5261e05 100644 --- a/src/filters/convolvematrix.h +++ b/src/filters/convolvematrix.h @@ -1,8 +1,5 @@ -#ifndef SP_FECONVOLVEMATRIX_H_SEEN -#define SP_FECONVOLVEMATRIX_H_SEEN - -/** \file - * SVG <feConvolveMatrix> implementation, see ConvolveMatrix.cpp. +/** @file + * @brief SVG matrix convolution filter effect */ /* * Authors: @@ -13,18 +10,23 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifndef SP_FECONVOLVEMATRIX_H_SEEN +#define SP_FECONVOLVEMATRIX_H_SEEN -#include "sp-filter.h" -#include "convolvematrix-fns.h" +#include <vector> +#include "sp-filter-primitive.h" #include "number-opt-number.h" #include "display/nr-filter-convolve-matrix.h" -#include <vector> -/* FeConvolveMatrix base class */ +#define SP_TYPE_FECONVOLVEMATRIX (sp_feConvolveMatrix_get_type()) +#define SP_FECONVOLVEMATRIX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FECONVOLVEMATRIX, SPFeConvolveMatrix)) +#define SP_FECONVOLVEMATRIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FECONVOLVEMATRIX, SPFeConvolveMatrixClass)) +#define SP_IS_FECONVOLVEMATRIX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FECONVOLVEMATRIX)) +#define SP_IS_FECONVOLVEMATRIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FECONVOLVEMATRIX)) + class SPFeConvolveMatrixClass; struct SPFeConvolveMatrix : public SPFilterPrimitive { - /* CONVOLVEMATRIX ATTRIBUTES */ NumberOptNumber order; std::vector<gdouble> kernelMatrix; double divisor, bias; @@ -32,7 +34,7 @@ struct SPFeConvolveMatrix : public SPFilterPrimitive { Inkscape::Filters::FilterConvolveMatrixEdgeMode edgeMode; NumberOptNumber kernelUnitLength; bool preserveAlpha; - //some helper variables: + bool targetXIsSet; bool targetYIsSet; bool divisorIsSet; @@ -45,7 +47,6 @@ struct SPFeConvolveMatrixClass { GType sp_feConvolveMatrix_get_type(); - #endif /* !SP_FECONVOLVEMATRIX_H_SEEN */ /* diff --git a/src/filters/diffuselighting-fns.h b/src/filters/diffuselighting-fns.h deleted file mode 100644 index 27ea77358..000000000 --- a/src/filters/diffuselighting-fns.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef SP_FEDIFFUSELIGHTING_FNS_H -#define SP_FEDIFFUSELIGHTING_FNS_H - -/** \file - * Macros and fn declarations related to gaussian blur filter. - */ - -#include <glib-object.h> -#include <glib/gtypes.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -class SPFeDiffuseLighting; - -#define SP_TYPE_FEDIFFUSELIGHTING (sp_feDiffuseLighting_get_type()) -#define SP_FEDIFFUSELIGHTING(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEDIFFUSELIGHTING, SPFeDiffuseLighting)) -#define SP_FEDIFFUSELIGHTING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEDIFFUSELIGHTING, SPFeDiffuseLightingClass)) -#define SP_IS_FEDIFFUSELIGHTING(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEDIFFUSELIGHTING)) -#define SP_IS_FEDIFFUSELIGHTING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEDIFFUSELIGHTING)) - -GType sp_feDiffuseLighting_get_type(); - -#endif /* !SP_FEDIFFUSELIGHTING_FNS_H */ - -/* - 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 : diff --git a/src/filters/diffuselighting.cpp b/src/filters/diffuselighting.cpp index 5c55a3d20..0f2f29d67 100644 --- a/src/filters/diffuselighting.cpp +++ b/src/filters/diffuselighting.cpp @@ -22,7 +22,11 @@ #include "svg/svg.h" #include "sp-object.h" #include "svg/svg-color.h" -#include "diffuselighting.h" +#include "filters/diffuselighting.h" +#include "filters/distantlight.h" +#include "filters/pointlight.h" +#include "filters/spotlight.h" +#include "display/nr-filter.h" #include "xml/repr.h" #include "display/nr-filter-diffuselighting.h" diff --git a/src/filters/diffuselighting.h b/src/filters/diffuselighting.h index 7f0d8bc7a..a23346622 100644 --- a/src/filters/diffuselighting.h +++ b/src/filters/diffuselighting.h @@ -1,46 +1,46 @@ -#ifndef SP_FEDIFFUSELIGHTING_H_SEEN -#define SP_FEDIFFUSELIGHTING_H_SEEN - -/** \file - * SVG <feDiffuseLighting> implementation, see DiffuseLighting.cpp. - */ -/* +/** @file + * @brief SVG diffuse lighting filter effect + *//* * Authors: * Hugo Rodrigues <haa.rodrigues@gmail.com> * Jean-Rene Reinhard <jr@komite.net> * - * Copyright (C) 2006 Hugo Rodrigues - * 2007 authors - * + * Copyright (C) 2006-2007 Authors * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "sp-filter.h" -#include "diffuselighting-fns.h" +#ifndef SP_FEDIFFUSELIGHTING_H_SEEN +#define SP_FEDIFFUSELIGHTING_H_SEEN + +#include "sp-filter-primitive.h" +#include "number-opt-number.h" namespace Inkscape { namespace Filters { class FilterDiffuseLighting; -} -} +} } + +#define SP_TYPE_FEDIFFUSELIGHTING (sp_feDiffuseLighting_get_type()) +#define SP_FEDIFFUSELIGHTING(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEDIFFUSELIGHTING, SPFeDiffuseLighting)) +#define SP_FEDIFFUSELIGHTING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEDIFFUSELIGHTING, SPFeDiffuseLightingClass)) +#define SP_IS_FEDIFFUSELIGHTING(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEDIFFUSELIGHTING)) +#define SP_IS_FEDIFFUSELIGHTING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEDIFFUSELIGHTING)) + +namespace Inkscape { +namespace Filters { +class FilterDiffuseLighting; +} } -/* FeDiffuseLighting base class */ class SPFeDiffuseLightingClass; struct SPFeDiffuseLighting : public SPFilterPrimitive { - /** DIFFUSELIGHTING ATTRIBUTES HERE */ - /** surfaceScale attribute */ gfloat surfaceScale; guint surfaceScale_set : 1; - /** diffuseConstant attribute */ gfloat diffuseConstant; guint diffuseConstant_set : 1; - /** kernelUnitLength attribute */ NumberOptNumber kernelUnitLength; - /** lighting-color property */ guint32 lighting_color; guint lighting_color_set : 1; - /** pointer to the associated renderer */ Inkscape::Filters::FilterDiffuseLighting *renderer; }; @@ -50,7 +50,6 @@ struct SPFeDiffuseLightingClass { GType sp_feDiffuseLighting_get_type(); - #endif /* !SP_FEDIFFUSELIGHTING_H_SEEN */ /* diff --git a/src/filters/displacementmap-fns.h b/src/filters/displacementmap-fns.h deleted file mode 100644 index 2fc115bb8..000000000 --- a/src/filters/displacementmap-fns.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef SP_FEDISPLACEMENTMAP_FNS_H -#define SP_FEDISPLACEMENTMAP_FNS_H - -/** \file - * Macros and fn declarations related to gaussian blur filter. - */ - -#include <glib-object.h> -#include <glib/gtypes.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -class SPFeDisplacementMap; - -#define SP_TYPE_FEDISPLACEMENTMAP (sp_feDisplacementMap_get_type()) -#define SP_FEDISPLACEMENTMAP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEDISPLACEMENTMAP, SPFeDisplacementMap)) -#define SP_FEDISPLACEMENTMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEDISPLACEMENTMAP, SPFeDisplacementMapClass)) -#define SP_IS_FEDISPLACEMENTMAP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEDISPLACEMENTMAP)) -#define SP_IS_FEDISPLACEMENTMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEDISPLACEMENTMAP)) - -GType sp_feDisplacementMap_get_type(); - -#endif /* !SP_FEDISPLACEMENTMAP_FNS_H */ - -/* - 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 : diff --git a/src/filters/displacementmap.cpp b/src/filters/displacementmap.cpp index a6ad8b81a..69a678c26 100644 --- a/src/filters/displacementmap.cpp +++ b/src/filters/displacementmap.cpp @@ -18,10 +18,12 @@ #include "attributes.h" #include "svg/svg.h" -#include "displacementmap.h" +#include "filters/displacementmap.h" #include "xml/repr.h" -#include "display/nr-filter-displacement-map.h" +#include "sp-filter.h" #include "helper-fns.h" +#include "display/nr-filter.h" +#include "display/nr-filter-displacement-map.h" /* FeDisplacementMap base class */ diff --git a/src/filters/displacementmap.h b/src/filters/displacementmap.h index f3c596f11..6232f0937 100644 --- a/src/filters/displacementmap.h +++ b/src/filters/displacementmap.h @@ -1,10 +1,6 @@ -#ifndef SP_FEDISPLACEMENTMAP_H_SEEN -#define SP_FEDISPLACEMENTMAP_H_SEEN - /** \file - * SVG <feDisplacementMap> implementation, see DisplacementMap.cpp. - */ -/* + * SVG displacement map filter effect + *//* * Authors: * Hugo Rodrigues <haa.rodrigues@gmail.com> * @@ -13,8 +9,16 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "sp-filter.h" -#include "displacementmap-fns.h" +#ifndef SP_FEDISPLACEMENTMAP_H_SEEN +#define SP_FEDISPLACEMENTMAP_H_SEEN + +#include "sp-filter-primitive.h" + +#define SP_TYPE_FEDISPLACEMENTMAP (sp_feDisplacementMap_get_type()) +#define SP_FEDISPLACEMENTMAP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEDISPLACEMENTMAP, SPFeDisplacementMap)) +#define SP_FEDISPLACEMENTMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEDISPLACEMENTMAP, SPFeDisplacementMapClass)) +#define SP_IS_FEDISPLACEMENTMAP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEDISPLACEMENTMAP)) +#define SP_IS_FEDISPLACEMENTMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEDISPLACEMENTMAP)) enum FilterDisplacementMapChannelSelector { DISPLACEMENTMAP_CHANNEL_RED, @@ -24,11 +28,9 @@ enum FilterDisplacementMapChannelSelector { DISPLACEMENTMAP_CHANNEL_ENDTYPE }; -/* FeDisplacementMap base class */ class SPFeDisplacementMapClass; struct SPFeDisplacementMap : public SPFilterPrimitive { - /** DISPLACEMENTMAP ATTRIBUTES HERE */ int in2; double scale; FilterDisplacementMapChannelSelector xChannelSelector; @@ -41,7 +43,6 @@ struct SPFeDisplacementMapClass { GType sp_feDisplacementMap_get_type(); - #endif /* !SP_FEDISPLACEMENTMAP_H_SEEN */ /* diff --git a/src/filters/distantlight.cpp b/src/filters/distantlight.cpp index 88c2a21ff..891049415 100644 --- a/src/filters/distantlight.cpp +++ b/src/filters/distantlight.cpp @@ -21,9 +21,9 @@ #include "attributes.h" #include "document.h" -#include "distantlight.h" -#include "diffuselighting-fns.h" -#include "specularlighting-fns.h" +#include "filters/distantlight.h" +#include "filters/diffuselighting.h" +#include "filters/specularlighting.h" #include "xml/repr.h" #define SP_MACROS_SILENT diff --git a/src/filters/flood-fns.h b/src/filters/flood-fns.h deleted file mode 100644 index 55130a7ba..000000000 --- a/src/filters/flood-fns.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef SP_FEFLOOD_FNS_H -#define SP_FEFLOOD_FNS_H - -/** \file - * Macros and fn declarations related to gaussian blur filter. - */ - -#include <glib-object.h> -#include <glib/gtypes.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -class SPFeFlood; - -#define SP_TYPE_FEFLOOD (sp_feFlood_get_type()) -#define SP_FEFLOOD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEFLOOD, SPFeFlood)) -#define SP_FEFLOOD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEFLOOD, SPFeFloodClass)) -#define SP_IS_FEFLOOD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEFLOOD)) -#define SP_IS_FEFLOOD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEFLOOD)) - -GType sp_feFlood_get_type(); - -#endif /* !SP_FEFLOOD_FNS_H */ - -/* - 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 : diff --git a/src/filters/flood.cpp b/src/filters/flood.cpp index 741c9e984..3de1eb527 100644 --- a/src/filters/flood.cpp +++ b/src/filters/flood.cpp @@ -20,9 +20,12 @@ #include "attributes.h" #include "svg/svg.h" -#include "flood.h" +#include "svg/svg-color.h" +#include "filters/flood.h" #include "xml/repr.h" #include "helper-fns.h" +#include "display/nr-filter.h" +#include "display/nr-filter-flood.h" /* FeFlood base class */ diff --git a/src/filters/flood.h b/src/filters/flood.h index 66b5dd96a..0083def70 100644 --- a/src/filters/flood.h +++ b/src/filters/flood.h @@ -1,10 +1,6 @@ -#ifndef SP_FEFLOOD_H_SEEN -#define SP_FEFLOOD_H_SEEN - -/** \file - * SVG <feFlood> implementation, see Flood.cpp. - */ -/* +/** @file + * @brief SVG flood filter effect + *//* * Authors: * Hugo Rodrigues <haa.rodrigues@gmail.com> * @@ -13,18 +9,21 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "sp-filter.h" -#include "flood-fns.h" +#ifndef SP_FEFLOOD_H_SEEN +#define SP_FEFLOOD_H_SEEN + +#include "sp-filter-primitive.h" #include "svg/svg-icc-color.h" -#include "display/nr-filter.h" -#include "display/nr-filter-flood.h" +#define SP_TYPE_FEFLOOD (sp_feFlood_get_type()) +#define SP_FEFLOOD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEFLOOD, SPFeFlood)) +#define SP_FEFLOOD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEFLOOD, SPFeFloodClass)) +#define SP_IS_FEFLOOD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEFLOOD)) +#define SP_IS_FEFLOOD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEFLOOD)) -/* FeFlood base class */ class SPFeFloodClass; struct SPFeFlood : public SPFilterPrimitive { - /** FLOOD ATTRIBUTES HERE */ guint32 color; SVGICCColor *icc; double opacity; diff --git a/src/sp-gaussian-blur.cpp b/src/filters/gaussian-blur.cpp index 3786d9094..ee1af8904 100644 --- a/src/sp-gaussian-blur.cpp +++ b/src/filters/gaussian-blur.cpp @@ -19,7 +19,7 @@ #include "attributes.h" #include "svg/svg.h" -#include "sp-gaussian-blur.h" +#include "filters/gaussian-blur.h" #include "xml/repr.h" #include "display/nr-filter.h" diff --git a/src/sp-gaussian-blur-fns.h b/src/filters/gaussian-blur.h index ab2c851cf..417f8a6f4 100644 --- a/src/sp-gaussian-blur-fns.h +++ b/src/filters/gaussian-blur.h @@ -1,20 +1,19 @@ -#ifndef SP_GAUSSIANBLUR_FNS_H -#define SP_GAUSSIANBLUR_FNS_H - -/** \file - * Macros and fn declarations related to gaussian blur filter. +/** @file + * @brief SVG Gaussian blur filter effect + *//* + * Authors: + * Hugo Rodrigues <haa.rodrigues@gmail.com> + * + * Copyright (C) 2006 Hugo Rodrigues + * + * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glib-object.h> -#include <glib/gtypes.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} +#ifndef SP_GAUSSIANBLUR_H_SEEN +#define SP_GAUSSIANBLUR_H_SEEN -class SPGaussianBlur; +#include "sp-filter-primitive.h" +#include "number-opt-number.h" #define SP_TYPE_GAUSSIANBLUR (sp_gaussianBlur_get_type()) #define SP_GAUSSIANBLUR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_GAUSSIANBLUR, SPGaussianBlur)) @@ -22,11 +21,23 @@ class SPGaussianBlur; #define SP_IS_GAUSSIANBLUR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_GAUSSIANBLUR)) #define SP_IS_GAUSSIANBLUR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_GAUSSIANBLUR)) +/* GaussianBlur base class */ +class SPGaussianBlurClass; + +struct SPGaussianBlur : public SPFilterPrimitive { + /** stdDeviation attribute */ + NumberOptNumber stdDeviation; +}; + +struct SPGaussianBlurClass { + SPFilterPrimitiveClass parent_class; +}; + GType sp_gaussianBlur_get_type(); void sp_gaussianBlur_setDeviation(SPGaussianBlur *blur, float num); void sp_gaussianBlur_setDeviation(SPGaussianBlur *blur, float num, float optnum); -#endif /* !SP_GAUSSIANBLUR_FNS_H */ +#endif /* !SP_GAUSSIANBLUR_H_SEEN */ /* Local Variables: diff --git a/src/filters/image-fns.h b/src/filters/image-fns.h deleted file mode 100644 index d9de38342..000000000 --- a/src/filters/image-fns.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef SP_FEIMAGE_FNS_H -#define SP_FEIMAGE_FNS_H - -/** \file - * Macros and fn declarations related to gaussian blur filter. - */ - -#include <glib-object.h> -#include <glib/gtypes.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -class SPFeImage; - -#define SP_TYPE_FEIMAGE (sp_feImage_get_type()) -#define SP_FEIMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEIMAGE, SPFeImage)) -#define SP_FEIMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEIMAGE, SPFeImageClass)) -#define SP_IS_FEIMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEIMAGE)) -#define SP_IS_FEIMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEIMAGE)) - -GType sp_feImage_get_type(); - -#endif /* !SP_FEIMAGE_FNS_H */ - -/* - 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 : diff --git a/src/filters/image.h b/src/filters/image.h index 535dd80fa..b4081602a 100644 --- a/src/filters/image.h +++ b/src/filters/image.h @@ -1,10 +1,6 @@ -#ifndef SP_FEIMAGE_H_SEEN -#define SP_FEIMAGE_H_SEEN - -/** \file - * SVG <feImage> implementation, see Image.cpp. - */ -/* +/** @file + * @brief SVG image filter effect + *//* * Authors: * Felipe CorrĂȘa da Silva Sanches <juca@members.fsf.org> * Hugo Rodrigues <haa.rodrigues@gmail.com> @@ -14,17 +10,23 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "sp-filter.h" -#include "image-fns.h" +#ifndef SP_FEIMAGE_H_SEEN +#define SP_FEIMAGE_H_SEEN + +#include "sp-filter-primitive.h" #include "svg/svg-length.h" #include "sp-item.h" #include "uri-references.h" -/* FeImage base class */ +#define SP_TYPE_FEIMAGE (sp_feImage_get_type()) +#define SP_FEIMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEIMAGE, SPFeImage)) +#define SP_FEIMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEIMAGE, SPFeImageClass)) +#define SP_IS_FEIMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEIMAGE)) +#define SP_IS_FEIMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEIMAGE)) + class SPFeImageClass; struct SPFeImage : public SPFilterPrimitive { - /** IMAGE ATTRIBUTES HERE */ gchar *href; /* preserveAspectRatio */ @@ -45,7 +47,6 @@ struct SPFeImageClass { GType sp_feImage_get_type(); - #endif /* !SP_FEIMAGE_H_SEEN */ /* diff --git a/src/filters/merge-fns.h b/src/filters/merge-fns.h deleted file mode 100644 index e3674a391..000000000 --- a/src/filters/merge-fns.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef SP_FEMERGE_FNS_H -#define SP_FEMERGE_FNS_H - -/** \file - * Macros and fn declarations related to gaussian blur filter. - */ - -#include <glib-object.h> -#include <glib/gtypes.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -class SPFeMerge; - -#define SP_TYPE_FEMERGE (sp_feMerge_get_type()) -#define SP_FEMERGE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEMERGE, SPFeMerge)) -#define SP_FEMERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEMERGE, SPFeMergeClass)) -#define SP_IS_FEMERGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEMERGE)) -#define SP_IS_FEMERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEMERGE)) - -GType sp_feMerge_get_type(); - -#endif /* !SP_FEMERGE_FNS_H */ - -/* - 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 : diff --git a/src/filters/merge.cpp b/src/filters/merge.cpp index 226c82a72..47830c38b 100644 --- a/src/filters/merge.cpp +++ b/src/filters/merge.cpp @@ -23,6 +23,7 @@ #include "merge.h" #include "mergenode.h" +#include "display/nr-filter.h" #include "display/nr-filter-merge.h" /* FeMerge base class */ diff --git a/src/filters/merge.h b/src/filters/merge.h index 93374d134..3243073ca 100644 --- a/src/filters/merge.h +++ b/src/filters/merge.h @@ -1,22 +1,23 @@ -#ifndef SP_FEMERGE_H_SEEN -#define SP_FEMERGE_H_SEEN - /** \file - * SVG <feMerge> implementation, see Merge.cpp. - */ -/* + * SVG merge filter effect + *//* * Authors: * Hugo Rodrigues <haa.rodrigues@gmail.com> * * Copyright (C) 2006 Hugo Rodrigues - * * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifndef SP_FEMERGE_H_SEEN +#define SP_FEMERGE_H_SEEN + +#include "sp-filter-primitive.h" -#include "sp-filter.h" -#include "merge-fns.h" +#define SP_TYPE_FEMERGE (sp_feMerge_get_type()) +#define SP_FEMERGE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEMERGE, SPFeMerge)) +#define SP_FEMERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEMERGE, SPFeMergeClass)) +#define SP_IS_FEMERGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEMERGE)) +#define SP_IS_FEMERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEMERGE)) -/* FeMerge base class */ class SPFeMergeClass; struct SPFeMerge : public SPFilterPrimitive { diff --git a/src/filters/mergenode.cpp b/src/filters/mergenode.cpp index b2aea5cca..639928305 100644 --- a/src/filters/mergenode.cpp +++ b/src/filters/mergenode.cpp @@ -19,8 +19,9 @@ #include "attributes.h" #include "xml/repr.h" -#include "mergenode.h" -#include "merge.h" +#include "filters/mergenode.h" +#include "filters/merge.h" +#include "display/nr-filter-types.h" static void sp_feMergeNode_class_init(SPFeMergeNodeClass *klass); static void sp_feMergeNode_init(SPFeMergeNode *skeleton); diff --git a/src/filters/morphology-fns.h b/src/filters/morphology-fns.h deleted file mode 100644 index dd023b607..000000000 --- a/src/filters/morphology-fns.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef SP_FEMORPHOLOGY_FNS_H -#define SP_FEMORPHOLOGY_FNS_H - -/** \file - * Macros and fn declarations related to gaussian blur filter. - */ - -#include <glib-object.h> -#include <glib/gtypes.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -class SPFeMorphology; - -#define SP_TYPE_FEMORPHOLOGY (sp_feMorphology_get_type()) -#define SP_FEMORPHOLOGY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEMORPHOLOGY, SPFeMorphology)) -#define SP_FEMORPHOLOGY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEMORPHOLOGY, SPFeMorphologyClass)) -#define SP_IS_FEMORPHOLOGY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEMORPHOLOGY)) -#define SP_IS_FEMORPHOLOGY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEMORPHOLOGY)) - -GType sp_feMorphology_get_type(); - -#endif /* !SP_FEMORPHOLOGY_FNS_H */ - -/* - 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 : diff --git a/src/filters/morphology.cpp b/src/filters/morphology.cpp index c6a7f9993..42327d59f 100644 --- a/src/filters/morphology.cpp +++ b/src/filters/morphology.cpp @@ -23,6 +23,7 @@ #include "svg/svg.h" #include "morphology.h" #include "xml/repr.h" +#include "display/nr-filter.h" #include "display/nr-filter-morphology.h" /* FeMorphology base class */ diff --git a/src/filters/morphology.h b/src/filters/morphology.h index 4a493d16c..b7005a3d9 100644 --- a/src/filters/morphology.h +++ b/src/filters/morphology.h @@ -1,10 +1,6 @@ -#ifndef SP_FEMORPHOLOGY_H_SEEN -#define SP_FEMORPHOLOGY_H_SEEN - /** \file - * SVG <feMorphology> implementation, see Morphology.cpp. - */ -/* + * @brief SVG morphology filter effect + *//* * Authors: * Hugo Rodrigues <haa.rodrigues@gmail.com> * @@ -13,18 +9,22 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "sp-filter.h" -#include "morphology-fns.h" +#ifndef SP_FEMORPHOLOGY_H_SEEN +#define SP_FEMORPHOLOGY_H_SEEN + +#include "sp-filter-primitive.h" #include "number-opt-number.h" -#include "display/nr-filter.h" #include "display/nr-filter-morphology.h" +#define SP_TYPE_FEMORPHOLOGY (sp_feMorphology_get_type()) +#define SP_FEMORPHOLOGY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEMORPHOLOGY, SPFeMorphology)) +#define SP_FEMORPHOLOGY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEMORPHOLOGY, SPFeMorphologyClass)) +#define SP_IS_FEMORPHOLOGY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEMORPHOLOGY)) +#define SP_IS_FEMORPHOLOGY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEMORPHOLOGY)) -/* FeMorphology base class */ class SPFeMorphologyClass; struct SPFeMorphology : public SPFilterPrimitive { - /** MORPHOLOGY ATTRIBUTES HERE */ Inkscape::Filters::FilterMorphologyOperator Operator; NumberOptNumber radius; }; diff --git a/src/filters/offset-fns.h b/src/filters/offset-fns.h deleted file mode 100644 index d9d2a2fc4..000000000 --- a/src/filters/offset-fns.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef SP_FEOFFSET_FNS_H -#define SP_FEOFFSET_FNS_H - -/** \file - * Macros and fn declarations related to gaussian blur filter. - */ - -#include <glib-object.h> -#include <glib/gtypes.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -class SPFeOffset; - -#define SP_TYPE_FEOFFSET (sp_feOffset_get_type()) -#define SP_FEOFFSET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEOFFSET, SPFeOffset)) -#define SP_FEOFFSET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEOFFSET, SPFeOffsetClass)) -#define SP_IS_FEOFFSET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEOFFSET)) -#define SP_IS_FEOFFSET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEOFFSET)) - -GType sp_feOffset_get_type(); - -#endif /* !SP_FEOFFSET_FNS_H */ - -/* - 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 : diff --git a/src/filters/offset.cpp b/src/filters/offset.cpp index 263e5bf06..f45169aba 100644 --- a/src/filters/offset.cpp +++ b/src/filters/offset.cpp @@ -19,9 +19,10 @@ #include "attributes.h" #include "svg/svg.h" -#include "offset.h" +#include "filters/offset.h" #include "helper-fns.h" #include "xml/repr.h" +#include "display/nr-filter.h" #include "display/nr-filter-offset.h" /* FeOffset base class */ diff --git a/src/filters/offset.h b/src/filters/offset.h index 49f8108ef..dba7ed8ef 100644 --- a/src/filters/offset.h +++ b/src/filters/offset.h @@ -1,10 +1,6 @@ -#ifndef SP_FEOFFSET_H_SEEN -#define SP_FEOFFSET_H_SEEN - -/** \file - * SVG <feOffset> implementation, see Offset.cpp. - */ -/* +/** @file + * @brief SVG offset filter effect + *//* * Authors: * Hugo Rodrigues <haa.rodrigues@gmail.com> * @@ -13,14 +9,20 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "sp-filter.h" -#include "offset-fns.h" +#ifndef SP_FEOFFSET_H_SEEN +#define SP_FEOFFSET_H_SEEN + +#include "sp-filter-primitive.h" + +#define SP_TYPE_FEOFFSET (sp_feOffset_get_type()) +#define SP_FEOFFSET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEOFFSET, SPFeOffset)) +#define SP_FEOFFSET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEOFFSET, SPFeOffsetClass)) +#define SP_IS_FEOFFSET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEOFFSET)) +#define SP_IS_FEOFFSET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEOFFSET)) -/* FeOffset base class */ class SPFeOffsetClass; struct SPFeOffset : public SPFilterPrimitive { - /** OFFSET ATTRIBUTES HERE */ double dx, dy; }; diff --git a/src/filters/pointlight.cpp b/src/filters/pointlight.cpp index 28b3ee165..ee6824d00 100644 --- a/src/filters/pointlight.cpp +++ b/src/filters/pointlight.cpp @@ -21,9 +21,9 @@ #include "attributes.h" #include "document.h" -#include "pointlight.h" -#include "diffuselighting-fns.h" -#include "specularlighting-fns.h" +#include "filters/pointlight.h" +#include "filters/diffuselighting.h" +#include "filters/specularlighting.h" #include "xml/repr.h" #define SP_MACROS_SILENT diff --git a/src/filters/specularlighting-fns.h b/src/filters/specularlighting-fns.h deleted file mode 100644 index 9fd5f46b3..000000000 --- a/src/filters/specularlighting-fns.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef SP_FESPECULARLIGHTING_FNS_H -#define SP_FESPECULARLIGHTING_FNS_H - -/** \file - * Macros and fn declarations related to gaussian blur filter. - */ - -#include <glib-object.h> -#include <glib/gtypes.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -class SPFeSpecularLighting; - -#define SP_TYPE_FESPECULARLIGHTING (sp_feSpecularLighting_get_type()) -#define SP_FESPECULARLIGHTING(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FESPECULARLIGHTING, SPFeSpecularLighting)) -#define SP_FESPECULARLIGHTING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FESPECULARLIGHTING, SPFeSpecularLightingClass)) -#define SP_IS_FESPECULARLIGHTING(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FESPECULARLIGHTING)) -#define SP_IS_FESPECULARLIGHTING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FESPECULARLIGHTING)) - -GType sp_feSpecularLighting_get_type(); - -#endif /* !SP_FESPECULARLIGHTING_FNS_H */ - -/* - 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 : diff --git a/src/filters/specularlighting.cpp b/src/filters/specularlighting.cpp index 27d2a8c02..71a705c94 100644 --- a/src/filters/specularlighting.cpp +++ b/src/filters/specularlighting.cpp @@ -22,8 +22,12 @@ #include "svg/svg.h" #include "sp-object.h" #include "svg/svg-color.h" -#include "specularlighting.h" +#include "filters/specularlighting.h" +#include "filters/distantlight.h" +#include "filters/pointlight.h" +#include "filters/spotlight.h" #include "xml/repr.h" +#include "display/nr-filter.h" #include "display/nr-filter-specularlighting.h" /* FeSpecularLighting base class */ diff --git a/src/filters/specularlighting.h b/src/filters/specularlighting.h index 692ec9bf9..90d1f9f62 100644 --- a/src/filters/specularlighting.h +++ b/src/filters/specularlighting.h @@ -1,10 +1,6 @@ -#ifndef SP_FESPECULARLIGHTING_H_SEEN -#define SP_FESPECULARLIGHTING_H_SEEN - -/** \file - * SVG <feSpecularLighting> implementation, see SpecularLighting.cpp. - */ -/* +/** @file + * @brief SVG specular lighting filter effect + *//* * Authors: * Hugo Rodrigues <haa.rodrigues@gmail.com> * Jean-Rene Reinhard <jr@komite.net> @@ -15,8 +11,17 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "sp-filter.h" -#include "specularlighting-fns.h" +#ifndef SP_FESPECULARLIGHTING_H_SEEN +#define SP_FESPECULARLIGHTING_H_SEEN + +#include "sp-filter-primitive.h" +#include "number-opt-number.h" + +#define SP_TYPE_FESPECULARLIGHTING (sp_feSpecularLighting_get_type()) +#define SP_FESPECULARLIGHTING(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FESPECULARLIGHTING, SPFeSpecularLighting)) +#define SP_FESPECULARLIGHTING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FESPECULARLIGHTING, SPFeSpecularLightingClass)) +#define SP_IS_FESPECULARLIGHTING(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FESPECULARLIGHTING)) +#define SP_IS_FESPECULARLIGHTING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FESPECULARLIGHTING)) namespace Inkscape { namespace Filters { @@ -24,23 +29,16 @@ class FilterSpecularLighting; } } -/* FeSpecularLighting base class */ class SPFeSpecularLightingClass; struct SPFeSpecularLighting : public SPFilterPrimitive { - /** SPECULARLIGHTING ATTRIBUTES HERE */ - /** surfaceScale attribute */ gfloat surfaceScale; guint surfaceScale_set : 1; - /** specularConstant attribute */ gfloat specularConstant; guint specularConstant_set : 1; - /** specularConstant attribute */ gfloat specularExponent; guint specularExponent_set : 1; - /** kernelUnitLenght attribute */ NumberOptNumber kernelUnitLength; - /** lighting-color property */ guint32 lighting_color; guint lighting_color_set : 1; diff --git a/src/filters/spotlight.cpp b/src/filters/spotlight.cpp index b6753a1f1..7be83ed00 100644 --- a/src/filters/spotlight.cpp +++ b/src/filters/spotlight.cpp @@ -21,9 +21,9 @@ #include "attributes.h" #include "document.h" -#include "spotlight.h" -#include "diffuselighting-fns.h" -#include "specularlighting-fns.h" +#include "filters/spotlight.h" +#include "filters/diffuselighting.h" +#include "filters/specularlighting.h" #include "xml/repr.h" #define SP_MACROS_SILENT diff --git a/src/filters/tile-fns.h b/src/filters/tile-fns.h deleted file mode 100644 index 5f8393a7b..000000000 --- a/src/filters/tile-fns.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef SP_FETILE_FNS_H -#define SP_FETILE_FNS_H - -/** \file - * Macros and fn declarations related to gaussian blur filter. - */ - -#include <glib-object.h> -#include <glib/gtypes.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -class SPFeTile; - -#define SP_TYPE_FETILE (sp_feTile_get_type()) -#define SP_FETILE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FETILE, SPFeTile)) -#define SP_FETILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FETILE, SPFeTileClass)) -#define SP_IS_FETILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FETILE)) -#define SP_IS_FETILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FETILE)) - -GType sp_feTile_get_type(); - -#endif /* !SP_FETILE_FNS_H */ - -/* - 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 : diff --git a/src/filters/tile.cpp b/src/filters/tile.cpp index f42ec1de5..c3555ee7c 100644 --- a/src/filters/tile.cpp +++ b/src/filters/tile.cpp @@ -19,9 +19,10 @@ #include "attributes.h" #include "svg/svg.h" -#include "tile.h" +#include "filters/tile.h" #include "xml/repr.h" - +#include "display/nr-filter.h" +#include "display/nr-filter-tile.h" /* FeTile base class */ diff --git a/src/filters/tile.h b/src/filters/tile.h index 747be7aa1..a376a6e10 100644 --- a/src/filters/tile.h +++ b/src/filters/tile.h @@ -1,10 +1,6 @@ -#ifndef SP_FETILE_H_SEEN -#define SP_FETILE_H_SEEN - -/** \file - * SVG <feTile> implementation, see Tile.cpp. - */ -/* +/** @file + * @brief SVG tile filter effect + *//* * Authors: * Hugo Rodrigues <haa.rodrigues@gmail.com> * @@ -13,17 +9,21 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "sp-filter.h" -#include "tile-fns.h" +#ifndef SP_FETILE_H_SEEN +#define SP_FETILE_H_SEEN -#include "display/nr-filter.h" -#include "display/nr-filter-tile.h" +#include "sp-filter-primitive.h" + +#define SP_TYPE_FETILE (sp_feTile_get_type()) +#define SP_FETILE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FETILE, SPFeTile)) +#define SP_FETILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FETILE, SPFeTileClass)) +#define SP_IS_FETILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FETILE)) +#define SP_IS_FETILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FETILE)) /* FeTile base class */ class SPFeTileClass; struct SPFeTile : public SPFilterPrimitive { - /** TILE ATTRIBUTES HERE */ }; @@ -33,7 +33,6 @@ struct SPFeTileClass { GType sp_feTile_get_type(); - #endif /* !SP_FETILE_H_SEEN */ /* diff --git a/src/filters/turbulence-fns.h b/src/filters/turbulence-fns.h deleted file mode 100644 index 33946e3da..000000000 --- a/src/filters/turbulence-fns.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef SP_FETURBULENCE_FNS_H -#define SP_FETURBULENCE_FNS_H - -/** \file - * Macros and fn declarations related to gaussian blur filter. - */ - -#include <glib-object.h> -#include <glib/gtypes.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -class SPFeTurbulence; - -#define SP_TYPE_FETURBULENCE (sp_feTurbulence_get_type()) -#define SP_FETURBULENCE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FETURBULENCE, SPFeTurbulence)) -#define SP_FETURBULENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FETURBULENCE, SPFeTurbulenceClass)) -#define SP_IS_FETURBULENCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FETURBULENCE)) -#define SP_IS_FETURBULENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FETURBULENCE)) - -GType sp_feTurbulence_get_type(); - -#endif /* !SP_FETURBULENCE_FNS_H */ - -/* - 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 : diff --git a/src/filters/turbulence.h b/src/filters/turbulence.h index a19b8df57..cbc4fb082 100644 --- a/src/filters/turbulence.h +++ b/src/filters/turbulence.h @@ -1,10 +1,6 @@ -#ifndef SP_FETURBULENCE_H_SEEN -#define SP_FETURBULENCE_H_SEEN - -/** \file - * SVG <feTurbulence> implementation, see Turbulence.cpp. - */ -/* +/** @file + * @brief SVG turbulence filter effect + *//* * Authors: * Felipe CorrĂȘa da Silva Sanches <juca@members.fsf.org> * Hugo Rodrigues <haa.rodrigues@gmail.com> @@ -14,11 +10,19 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "sp-filter.h" -#include "turbulence-fns.h" +#ifndef SP_FETURBULENCE_H_SEEN +#define SP_FETURBULENCE_H_SEEN + +#include "sp-filter-primitive.h" #include "number-opt-number.h" #include "display/nr-filter-turbulence.h" +#define SP_TYPE_FETURBULENCE (sp_feTurbulence_get_type()) +#define SP_FETURBULENCE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FETURBULENCE, SPFeTurbulence)) +#define SP_FETURBULENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FETURBULENCE, SPFeTurbulenceClass)) +#define SP_IS_FETURBULENCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FETURBULENCE)) +#define SP_IS_FETURBULENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FETURBULENCE)) + /* FeTurbulence base class */ class SPFeTurbulenceClass; diff --git a/src/flood-context.cpp b/src/flood-context.cpp index 4bec2f292..73e82607a 100644 --- a/src/flood-context.cpp +++ b/src/flood-context.cpp @@ -52,13 +52,7 @@ #include "display/nr-arena.h" #include "display/nr-arena-image.h" #include "display/canvas-arena.h" -#include "libnr/nr-pixops.h" -#include "libnr/nr-matrix-translate-ops.h" -#include "libnr/nr-scale-ops.h" -#include "libnr/nr-scale-translate-ops.h" -#include "libnr/nr-translate-matrix-ops.h" -#include "libnr/nr-translate-scale-ops.h" -#include "libnr/nr-matrix-ops.h" +#include "display/cairo-utils.h" #include <2geom/pathvector.h> #include "sp-item.h" #include "sp-root.h" @@ -206,22 +200,20 @@ static void sp_flood_context_setup(SPEventContext *ec) } } -/** - * \brief Merge a pixel with the background color. - * \param orig The pixel to merge with the background. - * \param bg The background color. - * \param base The pixel to merge the original and background into. - */ -inline static void -merge_pixel_with_background (unsigned char *orig, unsigned char *bg, - unsigned char *base) +inline static guint32 +compose_onto (guint32 px, guint32 bg) { - int precalc_bg_alpha = (255 * (255 - bg[3])) / 255; - - for (int i = 0; i < 3; i++) { - base[i] = precalc_bg_alpha + (bg[i] * bg[3]) / 255; - base[i] = (base[i] * (255 - orig[3])) / 255 + (orig[i] * orig[3]) / 255; - } + EXTRACT_ARGB32(px, ap,rp,gp,bp) + EXTRACT_ARGB32(bg, ab,rb,gb,bb) + guint32 ao,ro,bo,go; + + ao = 255*255 - (255-ap)*(255-bp); ao = (ao + 127) / 255; + ro = (255-ap)*rb + rp; ro = (ro + 127) / 255; + go = (255-ap)*gb + gp; go = (go + 127) / 255; + bo = (255-ap)*bb + bp; bo = (bo + 127) / 255; + + ASSEMBLE_ARGB32(pxout, ao,ro,go,bo) + return pxout; } /** @@ -229,10 +221,10 @@ merge_pixel_with_background (unsigned char *orig, unsigned char *bg, * \param px The pixel buffer. * \param x The X coordinate. * \param y The Y coordinate. - * \param width The width of the pixel buffer. + * \param stride The rowstride of the pixel buffer. */ -inline unsigned char * get_pixel(guchar *px, int x, int y, int width) { - return px + (x + y * width) * 4; +inline guint32 get_pixel(guchar *px, int x, int y, int stride) { + return *reinterpret_cast<guint32*>(px + y * stride + x * 4); } inline unsigned char * get_trace_pixel(guchar *trace_px, int x, int y, int width) { @@ -280,34 +272,44 @@ GList * flood_autogap_dropdown_items_list() { * \param threshold The fill threshold. * \param method The fill method to use as defined in PaintBucketChannels. */ -static bool compare_pixels(unsigned char *check, unsigned char *orig, unsigned char *merged_orig_pixel, unsigned char *dtc, int threshold, PaintBucketChannels method) { +static bool compare_pixels(guint32 check, guint32 orig, guint32 merged_orig_pixel, guint32 dtc, int threshold, PaintBucketChannels method) +{ int diff = 0; - float hsl_check[3], hsl_orig[3]; - + float hsl_check[3] = {0,0,0}, hsl_orig[3] = {0,0,0}; + + EXTRACT_ARGB32(check, ac,rc,gc,bc) + EXTRACT_ARGB32(orig, ao,ro,go,bo) + EXTRACT_ARGB32(dtc, ad,rd,gd,bd) + EXTRACT_ARGB32(merged_orig_pixel, amop,rmop,gmop,bmop) + if ((method == FLOOD_CHANNELS_H) || (method == FLOOD_CHANNELS_S) || (method == FLOOD_CHANNELS_L)) { - sp_color_rgb_to_hsl_floatv(hsl_check, check[0] / 255.0, check[1] / 255.0, check[2] / 255.0); - sp_color_rgb_to_hsl_floatv(hsl_orig, orig[0] / 255.0, orig[1] / 255.0, orig[2] / 255.0); + double dac = ac; + double dao = ao; + sp_color_rgb_to_hsl_floatv(hsl_check, rc / dac, gc / dac, bc / dac); + sp_color_rgb_to_hsl_floatv(hsl_orig, ro / dao, go / dao, bo / dao); } switch (method) { case FLOOD_CHANNELS_ALPHA: - return ((int)abs(check[3] - orig[3]) <= threshold); + return abs(static_cast<int>(ac) - ao) <= threshold; case FLOOD_CHANNELS_R: - return ((int)abs(check[0] - orig[0]) <= threshold); + return abs(static_cast<int>(ac ? unpremul_alpha(rc, ac) : 0) - (ao ? unpremul_alpha(ro, ao) : 0)) <= threshold; case FLOOD_CHANNELS_G: - return ((int)abs(check[1] - orig[1]) <= threshold); + return abs(static_cast<int>(ac ? unpremul_alpha(gc, ac) : 0) - (ao ? unpremul_alpha(go, ao) : 0)) <= threshold; case FLOOD_CHANNELS_B: - return ((int)abs(check[2] - orig[2]) <= threshold); + return abs(static_cast<int>(ac ? unpremul_alpha(bc, ac) : 0) - (ao ? unpremul_alpha(bo, ao) : 0)) <= threshold; case FLOOD_CHANNELS_RGB: - unsigned char merged_check[3]; - - merge_pixel_with_background(check, dtc, merged_check); - - for (int i = 0; i < 3; i++) { - diff += (int)abs(merged_check[i] - merged_orig_pixel[i]); - } + guint32 amc, rmc, bmc, gmc; + amc = 255*255 - (255-ac)*(255-ad); amc = (amc + 127) / 255; + rmc = (255-ac)*rd + rc; rmc = (rmc + 127) / 255; + gmc = (255-ac)*gd + gc; gmc = (gmc + 127) / 255; + bmc = (255-ac)*bd + bc; bmc = (bmc + 127) / 255; + + diff += abs(static_cast<int>(amc ? unpremul_alpha(rmc, amc) : 0) - (amop ? unpremul_alpha(rmop, amop) : 0)); + diff += abs(static_cast<int>(amc ? unpremul_alpha(gmc, amc) : 0) - (amop ? unpremul_alpha(gmop, amop) : 0)); + diff += abs(static_cast<int>(amc ? unpremul_alpha(bmc, amc) : 0) - (amop ? unpremul_alpha(bmop, amop) : 0)); return ((diff / 3) <= ((threshold * 3) / 4)); case FLOOD_CHANNELS_H: @@ -353,11 +355,12 @@ struct bitmap_coords_info { int y_limit; unsigned int width; unsigned int height; + unsigned int stride; unsigned int threshold; unsigned int radius; PaintBucketChannels method; - unsigned char *dtc; - unsigned char *merged_orig_pixel; + guint32 dtc; + guint32 merged_orig_pixel; Geom::Rect bbox; Geom::Rect screen; unsigned int max_queue_size; @@ -373,12 +376,12 @@ struct bitmap_coords_info { * \param orig_color The original selected pixel to use as the fill target color. * \param bci The bitmap_coords_info structure. */ -inline static bool check_if_pixel_is_paintable(guchar *px, unsigned char *trace_t, int x, int y, unsigned char *orig_color, bitmap_coords_info bci) { +inline static bool check_if_pixel_is_paintable(guchar *px, unsigned char *trace_t, int x, int y, guint32 orig_color, bitmap_coords_info bci) { if (is_pixel_paintability_checked(trace_t)) { return is_pixel_paintable(trace_t); } else { - unsigned char *t = get_pixel(px, x, y, bci.width); - if (compare_pixels(t, orig_color, bci.merged_orig_pixel, bci.dtc, bci.threshold, bci.method)) { + guint32 pixel = get_pixel(px, x, y, bci.stride); + if (compare_pixels(pixel, orig_color, bci.merged_orig_pixel, bci.dtc, bci.threshold, bci.method)) { mark_pixel_paintable(trace_t); return true; } else { @@ -557,7 +560,7 @@ inline static bool coords_in_range(unsigned int x, unsigned int y, bitmap_coords * \param bci The bitmap_coords_info structure. * \param original_point_trace_t The original pixel in the trace pixel buffer to check. */ -inline static unsigned int paint_pixel(guchar *px, guchar *trace_px, unsigned char *orig_color, bitmap_coords_info bci, unsigned char *original_point_trace_t) { +inline static unsigned int paint_pixel(guchar *px, guchar *trace_px, guint32 orig_color, bitmap_coords_info bci, unsigned char *original_point_trace_t) { if (bci.radius == 0) { mark_pixel_colored(original_point_trace_t); return PAINT_DIRECTION_ALL; @@ -639,7 +642,7 @@ static void shift_point_onto_queue(std::deque<Geom::Point> *fill_queue, unsigned * \param orig_color The original selected pixel to use as the fill target color. * \param bci The bitmap_coords_info structure. */ -static ScanlineCheckResult perform_bitmap_scanline_check(std::deque<Geom::Point> *fill_queue, guchar *px, guchar *trace_px, unsigned char *orig_color, bitmap_coords_info bci, unsigned int *min_x, unsigned int *max_x) { +static ScanlineCheckResult perform_bitmap_scanline_check(std::deque<Geom::Point> *fill_queue, guchar *px, guchar *trace_px, guint32 orig_color, bitmap_coords_info bci, unsigned int *min_x, unsigned int *max_x) { bool aborted = false; bool reached_screen_boundary = false; bool ok; @@ -823,37 +826,33 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even nr_arena_item_invoke_update(root, &final_bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); - guchar *px = g_new(guchar, 4 * width * height); - - NRPixBlock B; - nr_pixblock_setup_extern( &B, NR_PIXBLOCK_MODE_R8G8B8A8N, - final_bbox.x0, final_bbox.y0, final_bbox.x1, final_bbox.y1, - px, 4 * width, FALSE, FALSE ); + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); + guchar *px = g_new(guchar, stride * height); + cairo_surface_t *s = cairo_image_surface_create_for_data( + px, CAIRO_FORMAT_ARGB32, width, height, stride); + cairo_t *ct = cairo_create(s); + // cairo_translate not necessary here - surface origin is at 0,0 + SPNamedView *nv = sp_desktop_namedview(desktop); - unsigned long bgcolor = nv->pagecolor; - - unsigned char dtc[4]; - dtc[0] = NR_RGBA32_R(bgcolor); - dtc[1] = NR_RGBA32_G(bgcolor); - dtc[2] = NR_RGBA32_B(bgcolor); - dtc[3] = NR_RGBA32_A(bgcolor); - - for (unsigned int fy = 0; fy < height; fy++) { - guchar *p = NR_PIXBLOCK_PX(&B) + fy * B.rs; - for (unsigned int fx = 0; fx < width; fx++) { - for (int i = 0; i < 4; i++) { - *p++ = dtc[i]; - } - } - } + guint32 bgcolor = nv->pagecolor; + // bgcolor is 0xrrggbbaa, we need 0xaarrggbb + guint32 dtc = (bgcolor >> 8) | (bgcolor << 24); + + ink_cairo_set_source_rgba32(ct, bgcolor); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); + cairo_set_operator(ct, CAIRO_OPERATOR_OVER); - nr_arena_item_invoke_render(NULL, root, &final_bbox, &B, NR_ARENA_ITEM_RENDER_NO_CACHE ); - nr_pixblock_release(&B); + nr_arena_item_invoke_render(ct, root, &final_bbox, NULL, NR_ARENA_ITEM_RENDER_NO_CACHE ); + + cairo_surface_flush(s); + cairo_destroy(ct); + cairo_surface_destroy(s); // Hide items SP_ITEM(document->getRoot())->invoke_hide(dkey); - + nr_object_unref((NRObject *) arena); guchar *trace_px = g_new(guchar, width * height); @@ -890,6 +889,7 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even bci.y_limit = y_limit; bci.width = width; bci.height = height; + bci.stride = stride; bci.threshold = threshold; bci.method = method; bci.bbox = *bbox; @@ -942,15 +942,8 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even int cx = (int)color_point[Geom::X]; int cy = (int)color_point[Geom::Y]; - unsigned char *orig_px = get_pixel(px, cx, cy, width); - unsigned char orig_color[4]; - for (int i = 0; i < 4; i++) { orig_color[i] = orig_px[i]; } - - unsigned char merged_orig[3]; - - merge_pixel_with_background(orig_color, dtc, merged_orig); - - bci.merged_orig_pixel = merged_orig; + guint32 orig_color = get_pixel(px, cx, cy, stride); + bci.merged_orig_pixel = compose_onto(orig_color, dtc); unsigned char *trace_t = get_trace_pixel(trace_px, cx, cy, width); if (!is_pixel_checked(trace_t) && !is_pixel_colored(trace_t)) { diff --git a/src/gradient-chemistry.cpp b/src/gradient-chemistry.cpp index 889e319b2..676e9aa94 100644 --- a/src/gradient-chemistry.cpp +++ b/src/gradient-chemistry.cpp @@ -30,10 +30,6 @@ #include "sp-text.h" #include "sp-tspan.h" -#include <libnr/nr-matrix-fns.h> -#include <libnr/nr-point-fns.h> -#include <libnr/nr-matrix-ops.h> -#include <libnr/nr-rotate-ops.h> #include <2geom/transforms.h> #include "xml/repr.h" #include "svg/svg.h" @@ -41,6 +37,7 @@ #include "svg/css-ostringstream.h" #include "preferences.h" +#include "libnr/nr-point-fns.h" #define noSP_GR_VERBOSE // Terminology: diff --git a/src/gradient-context.cpp b/src/gradient-context.cpp index 007fa549a..922a9b16e 100644 --- a/src/gradient-context.cpp +++ b/src/gradient-context.cpp @@ -46,8 +46,9 @@ #include "sp-namedview.h" #include "rubberband.h" -using Inkscape::DocumentUndo; +#include "libnr/nr-point-fns.h" +using Inkscape::DocumentUndo; static void sp_gradient_context_class_init(SPGradientContextClass *klass); static void sp_gradient_context_init(SPGradientContext *gr_context); diff --git a/src/helper/geom.cpp b/src/helper/geom.cpp index 2420b43b4..64aa8bc48 100644 --- a/src/helper/geom.cpp +++ b/src/helper/geom.cpp @@ -28,8 +28,6 @@ using Geom::X; using Geom::Y; -#define NR_HUGE 1e18 - //################################################################################# // BOUNDING BOX CALCULATIONS @@ -423,7 +421,7 @@ pathv_matrix_point_bbox_wind_distance (Geom::PathVector const & pathv, Geom::Aff { if (pathv.empty()) { if (wind) *wind = 0; - if (dist) *dist = NR_HUGE; + if (dist) *dist = Geom::infinity(); return; } diff --git a/src/helper/pixbuf-ops.cpp b/src/helper/pixbuf-ops.cpp index acd2568af..f6796f2ad 100644 --- a/src/helper/pixbuf-ops.cpp +++ b/src/helper/pixbuf-ops.cpp @@ -15,28 +15,23 @@ # include "config.h" #endif -#include <interface.h> -#include <libnr/nr-pixops.h> #include <glib.h> #include <glib/gmessages.h> #include <png.h> -#include "png-write.h" -#include <display/nr-arena-item.h> -#include <display/nr-arena.h> -#include <document.h> -#include <sp-item.h> -#include <sp-root.h> -#include <sp-use.h> -#include <sp-defs.h> -#include "unit-constants.h" -#include "libnr/nr-matrix-translate-ops.h" -#include "libnr/nr-scale-ops.h" -#include "libnr/nr-scale-translate-ops.h" -#include "libnr/nr-translate-matrix-ops.h" -#include "libnr/nr-translate-scale-ops.h" +#include "interface.h" +#include "helper/png-write.h" +#include "display/cairo-utils.h" +#include "display/nr-arena-item.h" +#include "display/nr-arena.h" +#include "document.h" +#include "sp-item.h" +#include "sp-root.h" +#include "sp-use.h" +#include "sp-defs.h" +#include "unit-constants.h" -#include "pixbuf-ops.h" +#include "helper/pixbuf-ops.h" // TODO look for copy-n-past duplication of this function: /** @@ -155,50 +150,32 @@ sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/, nr_arena_item_invoke_update(root, &final_bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); - guchar *px = NULL; - guint64 size = 4L * (guint64)width * (guint64)height; - if(size < (guint64)G_MAXSIZE) { - // g_try_new is limited to g_size type which is defined as unisgned int. Need to test for very large nubers - px = g_try_new(guchar, size); - } + cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - if(px != NULL) - { + if (cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS) { + cairo_t *ct = cairo_create(surface); + + // clear to background + ink_cairo_set_source_rgba32(ct, bgcolor); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); + cairo_set_operator(ct, CAIRO_OPERATOR_OVER); + + // render items + nr_arena_item_invoke_render(ct, root, &final_bbox, NULL, NR_ARENA_ITEM_RENDER_NO_CACHE ); - NRPixBlock B; - //g_warning("sp_generate_internal_bitmap: nr_pixblock_setup_extern."); - nr_pixblock_setup_extern( &B, NR_PIXBLOCK_MODE_R8G8B8A8N, - final_bbox.x0, final_bbox.y0, final_bbox.x1, final_bbox.y1, - px, 4 * width, FALSE, FALSE ); - - unsigned char dtc[4]; - dtc[0] = NR_RGBA32_R(bgcolor); - dtc[1] = NR_RGBA32_G(bgcolor); - dtc[2] = NR_RGBA32_B(bgcolor); - dtc[3] = NR_RGBA32_A(bgcolor); - - // fill pixelblock using background colour - for (gsize fy = 0; fy < height; fy++) { - guchar *p = NR_PIXBLOCK_PX(&B) + fy * (gsize)B.rs; - for (unsigned int fx = 0; fx < width; fx++) { - for (int i = 0; i < 4; i++) { - *p++ = dtc[i]; - } - } - } - - - nr_arena_item_invoke_render(NULL, root, &final_bbox, &B, NR_ARENA_ITEM_RENDER_NO_CACHE ); - - pixbuf = gdk_pixbuf_new_from_data(px, GDK_COLORSPACE_RGB, - TRUE, - 8, width, height, width * 4, - (GdkPixbufDestroyNotify)g_free, - NULL); + pixbuf = gdk_pixbuf_new_from_data(cairo_image_surface_get_data(surface), + GDK_COLORSPACE_RGB, TRUE, + 8, width, height, cairo_image_surface_get_stride(surface), + (GdkPixbufDestroyNotify) cairo_surface_destroy, + NULL); + convert_pixbuf_argb32_to_normal(pixbuf); } else { + long long size = (long long) height * (long long) cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); g_warning("sp_generate_internal_bitmap: not enough memory to create pixel buffer. Need %lld.", size); + cairo_surface_destroy(surface); } SP_ITEM(doc->getRoot())->invoke_hide(dkey); nr_object_unref((NRObject *) arena); diff --git a/src/helper/png-write.cpp b/src/helper/png-write.cpp index 2df543c6d..4667f631b 100644 --- a/src/helper/png-write.cpp +++ b/src/helper/png-write.cpp @@ -16,22 +16,21 @@ # include "config.h" #endif -#include <interface.h> -#include <libnr/nr-pixops.h> -#include <libnr/nr-translate-scale-ops.h> +#include "interface.h" #include <2geom/rect.h> #include <glib/gmessages.h> #include <png.h> #include "png-write.h" #include "io/sys.h" -#include <display/nr-arena-item.h> -#include <display/nr-arena.h> -#include <document.h> -#include <sp-item.h> -#include <sp-root.h> -#include <sp-defs.h> +#include "display/nr-arena-item.h" +#include "display/nr-arena.h" +#include "document.h" +#include "sp-item.h" +#include "sp-root.h" +#include "sp-defs.h" #include "preferences.h" #include "rdf.h" +#include "display/cairo-utils.h" /* This is an example of how to use libpng to read and write PNG files. * The file libpng.txt is much more verbose then this. If you have not @@ -49,7 +48,7 @@ static unsigned int const MAX_STRIPE_SIZE = 1024*1024; struct SPEBP { unsigned long int width, height, sheight; - guchar r, g, b, a; + guint32 background; NRArenaItem *root; // the root arena item to show; it is assumed that all unneeded items are hidden guchar *px; unsigned (*status)(float, void *); @@ -122,7 +121,7 @@ void PngTextList::add(gchar const* key, gchar const* text) static bool sp_png_write_rgba_striped(SPDocument *doc, gchar const *filename, unsigned long int width, unsigned long int height, double xdpi, double ydpi, - int (* get_rows)(guchar const **rows, int row, int num_rows, void *data), + int (* get_rows)(guchar const **rows, void **to_free, int row, int num_rows, void *data), void *data) { struct SPEBP *ebp = (struct SPEBP *) data; @@ -272,10 +271,12 @@ sp_png_write_rgba_striped(SPDocument *doc, png_bytep* row_pointers = new png_bytep[ebp->sheight]; r = 0; - while (r < static_cast< png_uint_32 > (height) ) { - int n = get_rows((unsigned char const **) row_pointers, r, height-r, data); + while (r < static_cast<png_uint_32>(height)) { + void *to_free; + int n = get_rows((unsigned char const **) row_pointers, &to_free, r, height-r, data); if (!n) break; png_write_rows(png_ptr, row_pointers, n); + g_free(to_free); r += n; } @@ -305,7 +306,7 @@ sp_png_write_rgba_striped(SPDocument *doc, * */ static int -sp_export_get_rows(guchar const **rows, int row, int num_rows, void *data) +sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, void *data) { struct SPEBP *ebp = (struct SPEBP *) data; @@ -332,30 +333,35 @@ sp_export_get_rows(guchar const **rows, int row, int num_rows, void *data) nr_arena_item_invoke_update(ebp->root, &bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); - NRPixBlock pb; - nr_pixblock_setup_extern(&pb, NR_PIXBLOCK_MODE_R8G8B8A8N, - bbox.x0, bbox.y0, bbox.x1, bbox.y1, - ebp->px, 4 * ebp->width, FALSE, FALSE); + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, ebp->width); + unsigned char *px = g_new(guchar, num_rows * stride); - for (int r = 0; r < num_rows; r++) { - guchar *p = NR_PIXBLOCK_PX(&pb) + r * pb.rs; - for (int c = 0; c < static_cast<int>(ebp->width); c++) { - *p++ = ebp->r; - *p++ = ebp->g; - *p++ = ebp->b; - *p++ = ebp->a; - } - } + cairo_surface_t *s = cairo_image_surface_create_for_data( + px, CAIRO_FORMAT_ARGB32, ebp->width, num_rows, stride); + cairo_t *ct = cairo_create(s); + cairo_translate(ct, -bbox.x0, -bbox.y0); + + ink_cairo_set_source_rgba32(ct, ebp->background); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); + cairo_set_operator(ct, CAIRO_OPERATOR_OVER); /* Render */ - nr_arena_item_invoke_render(NULL, ebp->root, &bbox, &pb, 0); + nr_arena_item_invoke_render(ct, ebp->root, &bbox, NULL, 0); + + cairo_destroy(ct); + cairo_surface_destroy(s); + + *to_free = px; + + // PNG stores data as unpremultiplied big-endian RGBA, which means + // it's identical to the GdkPixbuf format. + convert_pixels_argb32_to_pixbuf(px, ebp->width, num_rows, stride); for (int r = 0; r < num_rows; r++) { - rows[r] = NR_PIXBLOCK_PX(&pb) + r * pb.rs; + rows[r] = px + r * stride; } - nr_pixblock_release(&pb); - return num_rows; } @@ -451,10 +457,7 @@ sp_export_png_file(SPDocument *doc, gchar const *filename, struct SPEBP ebp; ebp.width = width; ebp.height = height; - ebp.r = NR_RGBA32_R(bgcolor); - ebp.g = NR_RGBA32_G(bgcolor); - ebp.b = NR_RGBA32_B(bgcolor); - ebp.a = NR_RGBA32_A(bgcolor); + ebp.background = bgcolor; /* Create new arena */ NRArena *const arena = NRArena::create(); @@ -475,15 +478,12 @@ sp_export_png_file(SPDocument *doc, gchar const *filename, ebp.status = status; ebp.data = data; - bool write_status; - if ((width < 256) || ((width * height) < 32768)) { - ebp.px = nr_pixelstore_64K_new(FALSE, 0); - ebp.sheight = 65536 / (4 * width); - write_status = sp_png_write_rgba_striped(doc, filename, width, height, xdpi, ydpi, sp_export_get_rows, &ebp); - nr_pixelstore_64K_free(ebp.px); - } else { - ebp.sheight = 64; - ebp.px = g_try_new(guchar, 4 * ebp.sheight * width); + bool write_status = false;; + + ebp.sheight = 64; + ebp.px = g_try_new(guchar, 4 * ebp.sheight * width); + + if (ebp.px) { write_status = sp_png_write_rgba_striped(doc, filename, width, height, xdpi, ydpi, sp_export_get_rows, &ebp); g_free(ebp.px); } diff --git a/src/inkscape.cpp b/src/inkscape.cpp index e90c44c82..20084da54 100644 --- a/src/inkscape.cpp +++ b/src/inkscape.cpp @@ -25,10 +25,6 @@ # define HAS_PROC_SELF_EXE //to get path of executable #else -// For now to get at is_os_wide(). -# include "extension/internal/win32.h" -using Inkscape::Extension::Internal::PrintWin32; - #define _WIN32_IE 0x0400 //#define HAS_SHGetSpecialFolderPath #define HAS_SHGetSpecialFolderLocation @@ -1351,24 +1347,18 @@ profile_path(const char *filename) if ( SHGetSpecialFolderLocation( NULL, CSIDL_APPDATA, &pidl ) == NOERROR ) { gchar * utf8Path = NULL; - if ( PrintWin32::is_os_wide() ) { + { wchar_t pathBuf[MAX_PATH+1]; g_assert(sizeof(wchar_t) == sizeof(gunichar2)); if ( SHGetPathFromIDListW( pidl, pathBuf ) ) { utf8Path = g_utf16_to_utf8( (gunichar2*)(&pathBuf[0]), -1, NULL, NULL, NULL ); } - } else { - char pathBuf[MAX_PATH+1]; - - if ( SHGetPathFromIDListA( pidl, pathBuf ) ) { - utf8Path = g_filename_to_utf8( pathBuf, -1, NULL, NULL, NULL ); - } } if ( utf8Path ) { if (!g_utf8_validate(utf8Path, -1, NULL)) { - g_warning( "SHGetPathFromIDList%c() resulted in invalid UTF-8", (PrintWin32::is_os_wide() ? 'W' : 'A') ); + g_warning( "SHGetPathFromIDListW() resulted in invalid UTF-8"); g_free( utf8Path ); utf8Path = 0; } else { diff --git a/src/interface.cpp b/src/interface.cpp index f27700c25..11882ddf9 100644 --- a/src/interface.cpp +++ b/src/interface.cpp @@ -1267,7 +1267,7 @@ sp_ui_drag_data_received(GtkWidget *widget, ( !item->style->stroke.isNone() ? desktop->current_zoom() * item->style->stroke_width.computed * - to_2geom(item->i2d_affine()).descrim() * 0.5 + item->i2d_affine().descrim() * 0.5 : 0.0) + prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); @@ -1370,7 +1370,7 @@ sp_ui_drag_data_received(GtkWidget *widget, ( !item->style->stroke.isNone() ? desktop->current_zoom() * item->style->stroke_width.computed * - to_2geom(item->i2d_affine()).descrim() * 0.5 + item->i2d_affine().descrim() * 0.5 : 0.0) + prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); diff --git a/src/io/sys.cpp b/src/io/sys.cpp index 85857c2f0..437a9d18c 100644 --- a/src/io/sys.cpp +++ b/src/io/sys.cpp @@ -26,12 +26,6 @@ #include "preferences.h" #include "sys.h" -#ifdef WIN32 -// For now to get at is_os_wide(). -#include "extension/internal/win32.h" -using Inkscape::Extension::Internal::PrintWin32; -#endif // WIN32 - //#define INK_DUMP_FILENAME_CONV 1 #undef INK_DUMP_FILENAME_CONV diff --git a/src/io/uristream.cpp b/src/io/uristream.cpp index 05d7f020a..b5f884b29 100644 --- a/src/io/uristream.cpp +++ b/src/io/uristream.cpp @@ -16,12 +16,6 @@ #include <string> #include <cstring> -#ifdef WIN32 -// For now to get at is_os_wide(). -# include "extension/internal/win32.h" -using Inkscape::Extension::Internal::PrintWin32; -#endif - namespace Inkscape { @@ -65,7 +59,7 @@ static FILE *fopen_utf8name( char const *utf8name, int mode ) g_free(filename); } #else - if ( PrintWin32::is_os_wide() ) { + { gunichar2 *wideName = g_utf8_to_utf16( utf8name, -1, NULL, NULL, NULL ); if ( wideName ) { if (mode == FILE_READ) @@ -78,15 +72,6 @@ static FILE *fopen_utf8name( char const *utf8name, int mode ) g_message("Unable to convert filename from UTF-8 to UTF-16 [%s]", safe); g_free(safe); } - } else { - gchar *filename = g_filename_from_utf8( utf8name, -1, NULL, NULL, NULL ); - if ( filename ) { - if (mode == FILE_READ) - fp = std::fopen(filename, "rb"); - else - fp = std::fopen(filename, "wb"); - g_free(filename); - } } #endif diff --git a/src/knot-holder-entity.cpp b/src/knot-holder-entity.cpp index 81d845e99..7da3d0c0e 100644 --- a/src/knot-holder-entity.cpp +++ b/src/knot-holder-entity.cpp @@ -20,7 +20,6 @@ #include "style.h" #include "preferences.h" #include "macros.h" -#include <libnr/nr-matrix-ops.h> #include "sp-pattern.h" #include "snap.h" #include "desktop.h" diff --git a/src/libnr/Makefile_insert b/src/libnr/Makefile_insert index 8dd3c46e3..1027e0600 100644 --- a/src/libnr/Makefile_insert +++ b/src/libnr/Makefile_insert @@ -2,50 +2,17 @@ ink_common_sources += \ libnr/in-svg-plane.h \ - libnr/nr-blit.cpp \ - libnr/nr-blit.h \ - libnr/nr-compose-transform.cpp \ - libnr/nr-compose-transform.h \ - libnr/nr-compose-reference.h \ - libnr/nr-compose.cpp \ - libnr/nr-compose.h \ libnr/nr-convert2geom.h \ - libnr/nr-convex-hull.h \ libnr/nr-coord.h \ libnr/nr-dim2.h \ libnr/nr-forward.h \ - libnr/nr-gradient.cpp \ - libnr/nr-gradient.h \ libnr/nr-i-coord.h \ libnr/nr-macros.h \ - libnr/nr-matrix-div.cpp \ - libnr/nr-matrix-div.h \ - libnr/nr-matrix-fns.cpp \ - libnr/nr-matrix-fns.h \ - libnr/nr-matrix-ops.h \ - libnr/nr-matrix-rotate-ops.cpp \ - libnr/nr-matrix-rotate-ops.h \ - libnr/nr-matrix-scale-ops.h \ - libnr/nr-matrix-translate-ops.h \ - libnr/nr-matrix.cpp \ - libnr/nr-matrix.h \ - libnr/nr-maybe.h \ libnr/nr-object.cpp \ libnr/nr-object.h \ - libnr/nr-path-code.h \ - libnr/nr-pixblock-line.cpp \ - libnr/nr-pixblock-line.h \ - libnr/nr-pixblock-pattern.cpp \ - libnr/nr-pixblock-pattern.h \ - libnr/nr-pixblock-pixel.cpp \ - libnr/nr-pixblock-pixel.h \ - libnr/nr-pixblock.cpp \ - libnr/nr-pixblock.h \ - libnr/nr-pixops.h \ libnr/nr-point-fns.cpp \ libnr/nr-point-fns.h \ libnr/nr-point-l.h \ - libnr/nr-point-matrix-ops.h \ libnr/nr-point-ops.h \ libnr/nr-point.h \ libnr/nr-rect-l.cpp \ @@ -53,52 +20,15 @@ ink_common_sources += \ libnr/nr-rect.cpp \ libnr/nr-rect.h \ libnr/nr-rect-ops.h \ - libnr/nr-render.h \ - libnr/nr-rotate-fns.cpp \ - libnr/nr-rotate-fns.h \ - libnr/nr-rotate-ops.h \ - libnr/nr-rotate-matrix-ops.cpp \ - libnr/nr-rotate-matrix-ops.h \ - libnr/nr-rotate.h \ - libnr/nr-scale-matrix-ops.cpp \ - libnr/nr-scale-matrix-ops.h \ - libnr/nr-scale-translate-ops.cpp \ - libnr/nr-scale-translate-ops.h \ - libnr/nr-scale-ops.h \ - libnr/nr-scale.h \ - libnr/nr-translate-matrix-ops.cpp \ - libnr/nr-translate-matrix-ops.h \ - libnr/nr-translate-scale-ops.cpp \ - libnr/nr-translate-scale-ops.h \ - libnr/nr-translate-ops.h \ - libnr/nr-translate.h \ - libnr/nr-translate-rotate-ops.cpp \ - libnr/nr-translate-rotate-ops.h \ libnr/nr-types.cpp \ libnr/nr-types.h \ libnr/nr-values.cpp \ - libnr/nr-values.h \ - $(libnr_mmx_sources) - -# Ancient performance test (?) -# Won't work anymore. -#libnr_testnr_SOURCES = \ -# libnr/testnr.cpp - -#libnr_testnr_LDADD = \ -# libnr/libnr.a \ -# -lglib-2.0 + libnr/nr-values.h # ###################### # ### CxxTest stuff #### # ###################### CXXTEST_TESTSUITES += \ $(srcdir)/libnr/in-svg-plane-test.h \ - $(srcdir)/libnr/nr-compose-test.h \ - $(srcdir)/libnr/nr-matrix-test.h \ $(srcdir)/libnr/nr-point-fns-test.h \ - $(srcdir)/libnr/nr-rotate-test.h \ - $(srcdir)/libnr/nr-rotate-fns-test.h \ - $(srcdir)/libnr/nr-scale-test.h \ - $(srcdir)/libnr/nr-translate-test.h \ $(srcdir)/libnr/nr-types-test.h diff --git a/src/libnr/nr-blit.cpp b/src/libnr/nr-blit.cpp deleted file mode 100644 index 144caa597..000000000 --- a/src/libnr/nr-blit.cpp +++ /dev/null @@ -1,300 +0,0 @@ -#define __NR_BLIT_C__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * This code is in public domain - */ - -#include "nr-pixops.h" -#include "nr-compose.h" -#include "nr-blit.h" - -void -nr_blit_pixblock_pixblock_alpha (NRPixBlock *d, NRPixBlock *s, unsigned int alpha) -{ - NRRectL clip; - unsigned char *dpx, *spx; - int dbpp, sbpp; - int w, h; - - if (alpha == 0) return; - if (s->empty) return; - /* fixme: */ - if (s->mode == NR_PIXBLOCK_MODE_A8) return; - /* fixme: */ - if (s->mode == NR_PIXBLOCK_MODE_R8G8B8) return; - - /* - * Possible variants as of now: - * - * 0. SRC EP - DST EP * - * 1. SRC EP - DST EN * - * 2. SRC EP - DST P * - * 3. SRC EP - DST N * - * 4. SRC EN - DST EP * - * 5. SRC EN - DST EN * - * 6. SRC EN - DST P * - * 7. SRC EN - DST N * - * 8. SRC P - DST EP * - * 9. SRC P - DST EN * - * A. SRC P - DST P * - * B. SRC P - DST N * - * C. SRC N - DST EP * - * D. SRC N - DST EN * - * E. SRC N - DST P * - * F. SRC N - DST N * - * - */ - - nr_rect_l_intersect (&clip, &d->area, &s->area); - - if (nr_rect_l_test_empty(clip)) return; - - /* Pointers */ - dbpp = NR_PIXBLOCK_BPP (d); - dpx = NR_PIXBLOCK_PX (d) + (clip.y0 - d->area.y0) * d->rs + dbpp * (clip.x0 - d->area.x0); - sbpp = NR_PIXBLOCK_BPP (s); - spx = NR_PIXBLOCK_PX (s) + (clip.y0 - s->area.y0) * s->rs + sbpp * (clip.x0 - s->area.x0); - w = clip.x1 - clip.x0; - h = clip.y1 - clip.y0; - - switch (d->mode) { - case NR_PIXBLOCK_MODE_A8: - /* No rendering into alpha at moment */ - break; - case NR_PIXBLOCK_MODE_R8G8B8: - if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) { - nr_R8G8B8_R8G8B8_R8G8B8A8_P (dpx, w, h, d->rs, spx, s->rs, alpha); - } else { - nr_R8G8B8_R8G8B8_R8G8B8A8_N (dpx, w, h, d->rs, spx, s->rs, alpha); - } - break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: - if (d->empty) { - if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) { - /* Case 8 */ - nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P (dpx, w, h, d->rs, spx, s->rs, alpha); - } else { - /* Case C */ - nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N (dpx, w, h, d->rs, spx, s->rs, alpha); - } - } else { - if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) { - /* case A */ - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P (dpx, w, h, d->rs, spx, s->rs, alpha); - } else { - /* case E */ - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N (dpx, w, h, d->rs, spx, s->rs, alpha); - } - } - break; - case NR_PIXBLOCK_MODE_R8G8B8A8N: - if (d->empty) { - if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) { - /* Case 9 */ - nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P (dpx, w, h, d->rs, spx, s->rs, alpha); - } else { - /* Case D */ - nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N (dpx, w, h, d->rs, spx, s->rs, alpha); - } - } else { - if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) { - /* case B */ - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P (dpx, w, h, d->rs, spx, s->rs, alpha); - } else { - /* case F */ - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N (dpx, w, h, d->rs, spx, s->rs, alpha); - } - } - break; - } -} - -void -nr_blit_pixblock_pixblock_mask (NRPixBlock *d, NRPixBlock *s, NRPixBlock *m) -{ - NRRectL clip; - unsigned char *dpx, *spx, *mpx; - int dbpp, sbpp; - int w, h; - - if (s->empty) return; - /* fixme: */ - if (s->mode == NR_PIXBLOCK_MODE_A8) return; - /* fixme: */ - if (s->mode == NR_PIXBLOCK_MODE_R8G8B8) return; - - /* - * Possible variants as of now: - * - * 0. SRC EP - DST EP * - * 1. SRC EP - DST EN * - * 2. SRC EP - DST P * - * 3. SRC EP - DST N * - * 4. SRC EN - DST EP * - * 5. SRC EN - DST EN * - * 6. SRC EN - DST P * - * 7. SRC EN - DST N * - * 8. SRC P - DST EP * - * 9. SRC P - DST EN * - * A. SRC P - DST P * - * B. SRC P - DST N * - * C. SRC N - DST EP * - * D. SRC N - DST EN * - * E. SRC N - DST P * - * F. SRC N - DST N * - * - */ - - nr_rect_l_intersect (&clip, &d->area, &s->area); - nr_rect_l_intersect (&clip, &clip, &m->area); - - if (nr_rect_l_test_empty(clip)) return; - - /* Pointers */ - dbpp = NR_PIXBLOCK_BPP (d); - dpx = NR_PIXBLOCK_PX (d) + (clip.y0 - d->area.y0) * d->rs + dbpp * (clip.x0 - d->area.x0); - sbpp = NR_PIXBLOCK_BPP (s); - spx = NR_PIXBLOCK_PX (s) + (clip.y0 - s->area.y0) * s->rs + sbpp * (clip.x0 - s->area.x0); - mpx = NR_PIXBLOCK_PX (m) + (clip.y0 - m->area.y0) * m->rs + 1 * (clip.x0 - m->area.x0); - w = clip.x1 - clip.x0; - h = clip.y1 - clip.y0; - - switch (d->mode) { - case NR_PIXBLOCK_MODE_A8: - /* No rendering into alpha at moment */ - break; - case NR_PIXBLOCK_MODE_R8G8B8: - if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) { - nr_R8G8B8_R8G8B8_R8G8B8A8_P_A8 (dpx, w, h, d->rs, spx, s->rs, mpx, m->rs); - } else { - nr_R8G8B8_R8G8B8_R8G8B8A8_N_A8 (dpx, w, h, d->rs, spx, s->rs, mpx, m->rs); - } - break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: - if (d->empty) { - if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) { - /* Case 8 */ - nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8 (dpx, w, h, d->rs, spx, s->rs, mpx, m->rs); - } else { - /* Case C */ - nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8 (dpx, w, h, d->rs, spx, s->rs, mpx, m->rs); - } - } else { - if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) { - /* case A */ - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8 (dpx, w, h, d->rs, spx, s->rs, mpx, m->rs); - } else { - /* case E */ - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8 (dpx, w, h, d->rs, spx, s->rs, mpx, m->rs); - } - } - break; - case NR_PIXBLOCK_MODE_R8G8B8A8N: - if (d->empty) { - if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) { - /* Case 9 */ - nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8 (dpx, w, h, d->rs, spx, s->rs, mpx, m->rs); - } else { - /* Case D */ - nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8 (dpx, w, h, d->rs, spx, s->rs, mpx, m->rs); - } - } else { - if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) { - /* case B */ - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8 (dpx, w, h, d->rs, spx, s->rs, mpx, m->rs); - } else { - /* case F */ - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8 (dpx, w, h, d->rs, spx, s->rs, mpx, m->rs); - } - } - break; - } -} - -void -nr_blit_pixblock_mask_rgba32 (NRPixBlock *d, NRPixBlock *m, unsigned long rgba) -{ - if (!(rgba & 0xff)) return; - - if (m) { - NRRectL clip; - unsigned char *dpx, *mpx; - int w, h; - - if (m->mode != NR_PIXBLOCK_MODE_A8) return; - - if (!nr_rect_l_test_intersect(d->area, m->area)) return; - - nr_rect_l_intersect (&clip, &d->area, &m->area); - - /* Pointers */ - dpx = NR_PIXBLOCK_PX (d) + (clip.y0 - d->area.y0) * d->rs + NR_PIXBLOCK_BPP (d) * (clip.x0 - d->area.x0); - mpx = NR_PIXBLOCK_PX (m) + (clip.y0 - m->area.y0) * m->rs + (clip.x0 - m->area.x0); - w = clip.x1 - clip.x0; - h = clip.y1 - clip.y0; - - if (d->empty) { - if (d->mode == NR_PIXBLOCK_MODE_R8G8B8) { - nr_R8G8B8_R8G8B8_A8_RGBA32 (dpx, w, h, d->rs, mpx, m->rs, rgba); - } else if (d->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) { - nr_R8G8B8A8_P_EMPTY_A8_RGBA32 (dpx, w, h, d->rs, mpx, m->rs, rgba); - } else { - nr_R8G8B8A8_N_EMPTY_A8_RGBA32 (dpx, w, h, d->rs, mpx, m->rs, rgba); - } - d->empty = 0; - } else { - if (d->mode == NR_PIXBLOCK_MODE_R8G8B8) { - nr_R8G8B8_R8G8B8_A8_RGBA32 (dpx, w, h, d->rs, mpx, m->rs, rgba); - } else if (d->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) { - nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32 (dpx, w, h, d->rs, mpx, m->rs, rgba); - } else { - nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32 (dpx, w, h, d->rs, mpx, m->rs, rgba); - } - } - } else { - unsigned int r, g, b, a; - int x, y; - r = NR_RGBA32_R (rgba); - g = NR_RGBA32_G (rgba); - b = NR_RGBA32_B (rgba); - a = NR_RGBA32_A (rgba); - for (y = d->area.y0; y < d->area.y1; y++) { - unsigned char *p; - p = NR_PIXBLOCK_PX (d) + (y - d->area.y0) * d->rs; - for (x = d->area.x0; x < d->area.x1; x++) { - unsigned int da; - switch (d->mode) { - case NR_PIXBLOCK_MODE_R8G8B8: - p[0] = NR_COMPOSEN11_1111 (r, a, p[0]); - p[1] = NR_COMPOSEN11_1111 (g, a, p[1]); - p[2] = NR_COMPOSEN11_1111 (b, a, p[2]); - p += 3; - break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: - p[0] = NR_COMPOSENPP_1111 (r, a, p[0]); - p[1] = NR_COMPOSENPP_1111 (g, a, p[1]); - p[2] = NR_COMPOSENPP_1111 (b, a, p[2]); - p[3] = NR_COMPOSEA_111(a, p[3]); - p += 4; - break; - case NR_PIXBLOCK_MODE_R8G8B8A8N: - da = NR_COMPOSEA_112(a, p[3]); - p[0] = NR_COMPOSENNN_111121 (r, a, p[0], p[3], da); - p[1] = NR_COMPOSENNN_111121 (g, a, p[1], p[3], da); - p[2] = NR_COMPOSENNN_111121 (b, a, p[2], p[3], da); - p[3] = NR_NORMALIZE_21(da); - p += 4; - break; - default: - break; - } - } - } - } -} - diff --git a/src/libnr/nr-blit.h b/src/libnr/nr-blit.h deleted file mode 100644 index 9c2def114..000000000 --- a/src/libnr/nr-blit.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef __NR_BLIT_H__ -#define __NR_BLIT_H__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * This code is in public domain - */ - -#include <libnr/nr-pixblock.h> - -#define nr_blit_pixblock_pixblock(d,s) nr_blit_pixblock_pixblock_alpha (d, s, 255) - -void nr_blit_pixblock_pixblock_alpha (NRPixBlock *d, NRPixBlock *s, unsigned int alpha); -void nr_blit_pixblock_pixblock_mask (NRPixBlock *d, NRPixBlock *s, NRPixBlock *m); -void nr_blit_pixblock_mask_rgba32 (NRPixBlock *d, NRPixBlock *m, unsigned long rgba32); - -#endif - -/* - 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 : diff --git a/src/libnr/nr-compose-reference.cpp b/src/libnr/nr-compose-reference.cpp deleted file mode 100644 index b4ff5851a..000000000 --- a/src/libnr/nr-compose-reference.cpp +++ /dev/null @@ -1,266 +0,0 @@ - -// This is a reference implementation of the compositing functions in nr-compose.cpp. - -#include "nr-compose-reference.h" - -#define NR_RGBA32_R(v) (unsigned char) (((v) >> 24) & 0xff) -#define NR_RGBA32_G(v) (unsigned char) (((v) >> 16) & 0xff) -#define NR_RGBA32_B(v) (unsigned char) (((v) >> 8) & 0xff) -#define NR_RGBA32_A(v) (unsigned char) ((v) & 0xff) - -static inline unsigned int DIV_ROUND(unsigned int v, unsigned int divisor) { return (v+divisor/2)/divisor; } - -static unsigned int pixelSize[] = { 1, 3, 4, 4 }; - -// Computes : -// dc' = (1 - alpha*sa) * dc + alpha*sc -// da' = 1 - (1 - alpha*sa) * (1 - da) -// Assuming premultiplied color values -template<PIXEL_FORMAT resultFormat, PIXEL_FORMAT backgroundFormat, PIXEL_FORMAT foregroundFormat> -static void composePixel(unsigned char *d, const unsigned char *s, unsigned int alpha); - -template<> void composePixel<R8G8B8, R8G8B8, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) { - d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[0] + alpha*s[3]*s[0], 255*255); - d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[1] + alpha*s[3]*s[1], 255*255); - d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[2] + alpha*s[3]*s[2], 255*255); -} - -template<> void composePixel<R8G8B8, R8G8B8, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) { - d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[0] + 255*alpha*s[0], 255*255); - d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[1] + 255*alpha*s[1], 255*255); - d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[2] + 255*alpha*s[2], 255*255); -} - -template<> void composePixel<R8G8B8A8N, EMPTY, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) { - unsigned int newa = 255*255 - (255*255 - alpha*s[3]); - d[0] = s[0];//newa == 0 ? 0 : DIV_ROUND(alpha*s[3]*s[0], newa); - d[1] = s[1];//newa == 0 ? 0 : DIV_ROUND(alpha*s[3]*s[1], newa); - d[2] = s[2];//newa == 0 ? 0 : DIV_ROUND(alpha*s[3]*s[2], newa); - d[3] = DIV_ROUND(newa, 255); -} - -template<> void composePixel<R8G8B8A8N, EMPTY, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) { - unsigned int newa = 255*255 - (255*255 - alpha*s[3]); - d[0] = s[3] == 0 ? 0 : DIV_ROUND(255*s[0], s[3]);//newa == 0 ? 0 : DIV_ROUND(255*alpha*s[0], newa); - d[1] = s[3] == 0 ? 0 : DIV_ROUND(255*s[1], s[3]);//newa == 0 ? 0 : DIV_ROUND(255*alpha*s[1], newa); - d[2] = s[3] == 0 ? 0 : DIV_ROUND(255*s[2], s[3]);//newa == 0 ? 0 : DIV_ROUND(255*alpha*s[2], newa); - d[3] = DIV_ROUND(newa, 255); -} - -template<> void composePixel<R8G8B8A8N, R8G8B8A8N, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) { - if ( d[3] == 0 ) { - composePixel<R8G8B8A8N, EMPTY, R8G8B8A8N>(d, s, alpha); - } else if ( alpha*s[3] == 0 ) { - /* NOP */ - } else { - unsigned int newa = 255*255*255 - (255*255 - alpha*s[3]) * (255 - d[3]); - d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[0] + 255 * alpha*s[3]*s[0], newa); - d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[1] + 255 * alpha*s[3]*s[1], newa); - d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[2] + 255 * alpha*s[3]*s[2], newa); - d[3] = DIV_ROUND(newa, 255*255); - } -} - -template<> void composePixel<R8G8B8A8N, R8G8B8A8N, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) { - if ( d[3] == 0 ) { - composePixel<R8G8B8A8N, EMPTY, R8G8B8A8P>(d, s, alpha); - } else if ( alpha*s[3] == 0 ) { - /* NOP */ - } else { - unsigned int newa = 255*255*255 - (255*255 - alpha*s[3]) * (255 - d[3]); - d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[0] + 255*255 * alpha*s[0], newa); - d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[1] + 255*255 * alpha*s[1], newa); - d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[2] + 255*255 * alpha*s[2], newa); - d[3] = DIV_ROUND(newa, 255*255); - } -} - -template<> void composePixel<R8G8B8A8P, EMPTY, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) { - d[0] = DIV_ROUND(alpha*s[3]*s[0], 255*255); - d[1] = DIV_ROUND(alpha*s[3]*s[1], 255*255); - d[2] = DIV_ROUND(alpha*s[3]*s[2], 255*255); - d[3] = DIV_ROUND(255*255 - (255*255 - alpha*s[3]), 255); -} - -template<> void composePixel<R8G8B8A8P, EMPTY, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) { - d[0] = DIV_ROUND(alpha*s[0], 255); - d[1] = DIV_ROUND(alpha*s[1], 255); - d[2] = DIV_ROUND(alpha*s[2], 255); - d[3] = DIV_ROUND(255*255 - (255*255 - alpha*s[3]), 255); -} - -template<> void composePixel<R8G8B8A8P, R8G8B8A8P, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) { - d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[0] + alpha*s[3]*s[0], 255*255); - d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[1] + alpha*s[3]*s[1], 255*255); - d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[2] + alpha*s[3]*s[2], 255*255); - d[3] = DIV_ROUND(255*255*255 - (255*255 - alpha*s[3]) * (255 - d[3]), 255*255); -} - -template<> void composePixel<R8G8B8A8P, R8G8B8A8P, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) { - d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[0] + 255 * alpha*s[0], 255*255); - d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[1] + 255 * alpha*s[1], 255*255); - d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[2] + 255 * alpha*s[2], 255*255); - d[3] = DIV_ROUND(255*255*255 - (255*255 - alpha*s[3]) * (255 - d[3]), 255*255); -} - - -// composeAlpha, iterates over all pixels and applies composePixel to each of them -template<PIXEL_FORMAT resultFormat, PIXEL_FORMAT backgroundFormat, PIXEL_FORMAT foregroundFormat> -static void composeAlpha(unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { - for(int y=0; y<h; y++) { - unsigned char* d = px; - const unsigned char* s = spx; - for(int x=0; x<w; x++) { - composePixel<resultFormat, backgroundFormat, foregroundFormat>(d, s, alpha); - d += pixelSize[resultFormat]; - s += pixelSize[foregroundFormat]; - } - px += rs; - spx += srs; - } -} - -template<PIXEL_FORMAT resultFormat, PIXEL_FORMAT backgroundFormat, PIXEL_FORMAT foregroundFormat> -static void composeMask(unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) { - for(int y=0; y<h; y++) { - unsigned char* d = px; - const unsigned char* s = spx; - const unsigned char* m = mpx; - for(int x=0; x<w; x++) { - composePixel<resultFormat, backgroundFormat, foregroundFormat>(d, s, *m); - d += pixelSize[resultFormat]; - s += pixelSize[foregroundFormat]; - m += 1; - } - px += rs; - spx += srs; - mpx += mrs; - } -} - -template<PIXEL_FORMAT resultFormat, PIXEL_FORMAT backgroundFormat> -static void composeColor(unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba) { - const unsigned char rgba_array[4] = {NR_RGBA32_R(rgba), NR_RGBA32_G(rgba), NR_RGBA32_B(rgba), NR_RGBA32_A(rgba)}; - for(int y=0; y<h; y++) { - unsigned char* d = px; - const unsigned char* m = mpx; - for(int x=0; x<w; x++) { - composePixel<resultFormat, backgroundFormat, R8G8B8A8N>(d, rgba_array, *m); - d += pixelSize[resultFormat]; - m += 1; - } - px += rs; - mpx += mrs; - } -} - -/* FINAL DST SRC */ - -void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { - composeAlpha<R8G8B8A8N, EMPTY, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha); -} - -void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { - composeAlpha<R8G8B8A8N, EMPTY, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha); -} - -void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { - composeAlpha<R8G8B8A8P, EMPTY, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha); -} - -void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { - composeAlpha<R8G8B8A8P, EMPTY, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha); -} - - -void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { - composeAlpha<R8G8B8A8N, R8G8B8A8N, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha); -} - -void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { - composeAlpha<R8G8B8A8N, R8G8B8A8N, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha); -} - -void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { - composeAlpha<R8G8B8A8P, R8G8B8A8P, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha); -} - -void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { - composeAlpha<R8G8B8A8P, R8G8B8A8P, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha); -} - -/* FINAL DST SRC MASK */ - -void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) { - composeMask<R8G8B8A8N, EMPTY, R8G8B8A8N>(px, w, h, rs, spx, srs, mpx, mrs); -} - -void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) { - composeMask<R8G8B8A8N, EMPTY, R8G8B8A8P>(px, w, h, rs, spx, srs, mpx, mrs); -} - -void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) { - composeMask<R8G8B8A8P, EMPTY, R8G8B8A8N>(px, w, h, rs, spx, srs, mpx, mrs); -} - -void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) { - composeMask<R8G8B8A8P, EMPTY, R8G8B8A8P>(px, w, h, rs, spx, srs, mpx, mrs); -} - - -void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8_ref (unsigned char *p, int w, int h, int rs, const unsigned char *s, int srs, const unsigned char *m, int mrs) { - composeMask<R8G8B8A8N, R8G8B8A8N, R8G8B8A8N>(p, w, h, rs, s, srs, m, mrs); -} - -void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8_ref (unsigned char *p, int w, int h, int rs, const unsigned char *s, int srs, const unsigned char *m, int mrs) { - composeMask<R8G8B8A8N, R8G8B8A8N, R8G8B8A8P>(p, w, h, rs, s, srs, m, mrs); -} - -void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8_ref (unsigned char *p, int w, int h, int rs, const unsigned char *s, int srs, const unsigned char *m, int mrs) { - composeMask<R8G8B8A8P, R8G8B8A8P, R8G8B8A8N>(p, w, h, rs, s, srs, m, mrs); -} - -void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8_ref (unsigned char *p, int w, int h, int rs, const unsigned char *s, int srs, const unsigned char *m, int mrs) { - composeMask<R8G8B8A8P, R8G8B8A8P, R8G8B8A8P>(p, w, h, rs, s, srs, m, mrs); -} - -/* FINAL DST MASK COLOR */ - -void nr_R8G8B8A8_N_EMPTY_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba) { - composeColor<R8G8B8A8N, EMPTY>(px, w, h, rs, mpx, mrs, rgba); -} - -void nr_R8G8B8A8_P_EMPTY_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba) { - composeColor<R8G8B8A8P, EMPTY>(px, w, h, rs, mpx, mrs, rgba); -} - - -void nr_R8G8B8_R8G8B8_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba) { - composeColor<R8G8B8, R8G8B8>(px, w, h, rs, spx, srs, rgba); -} - -void nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba) { - composeColor<R8G8B8A8N, R8G8B8A8N>(px, w, h, rs, spx, srs, rgba); -} - -void nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba) { - composeColor<R8G8B8A8P, R8G8B8A8P>(px, w, h, rs, spx, srs, rgba); -} - -/* RGB */ - -void nr_R8G8B8_R8G8B8_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { - composeAlpha<R8G8B8, R8G8B8, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha); -} - -void nr_R8G8B8_R8G8B8_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { - composeAlpha<R8G8B8, R8G8B8, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha); -} - -void nr_R8G8B8_R8G8B8_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) { - composeMask<R8G8B8, R8G8B8, R8G8B8A8P>(px, w, h, rs, spx, srs, mpx, mrs); -} - -void nr_R8G8B8_R8G8B8_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) { - composeMask<R8G8B8, R8G8B8, R8G8B8A8N>(px, w, h, rs, spx, srs, mpx, mrs); -} diff --git a/src/libnr/nr-compose-reference.h b/src/libnr/nr-compose-reference.h deleted file mode 100644 index 8d004a135..000000000 --- a/src/libnr/nr-compose-reference.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef __NR_COMPOSE_REFERENCE_H__ -#define __NR_COMPOSE_REFERENCE_H__ - -// Based on nr-pixblock.h -typedef enum { - A8 = 0, - R8G8B8, - R8G8B8A8N, - R8G8B8A8P, - EMPTY = -1 -} PIXEL_FORMAT; - -/* FINAL DST SRC */ - -void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); -void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); -void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); -void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); - -void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); -void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); -void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); -void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); - -/* FINAL DST SRC MASK */ - -void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int srs, - const unsigned char *mpx, int mrs); -void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int srs, - const unsigned char *mpx, int mrs); -void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int srs, - const unsigned char *mpx, int mrs); -void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int srs, - const unsigned char *mpx, int mrs); - -void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8_ref (unsigned char *p, int w, int h, int rs, - const unsigned char *s, int srs, - const unsigned char *m, int mrs); -void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8_ref (unsigned char *p, int w, int h, int rs, - const unsigned char *s, int srs, - const unsigned char *m, int mrs); -void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8_ref (unsigned char *p, int w, int h, int rs, - const unsigned char *s, int srs, - const unsigned char *m, int mrs); -void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8_ref (unsigned char *p, int w, int h, int rs, - const unsigned char *s, int srs, - const unsigned char *m, int mrs); - -/* FINAL DST MASK COLOR */ - -void nr_R8G8B8A8_N_EMPTY_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba); -void nr_R8G8B8A8_P_EMPTY_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba); - -void nr_R8G8B8_R8G8B8_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba); -void nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba); -void nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba); - -/* RGB */ - -void nr_R8G8B8_R8G8B8_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); -void nr_R8G8B8_R8G8B8_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); -void nr_R8G8B8_R8G8B8_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs); -void nr_R8G8B8_R8G8B8_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs); - -#endif//__NR_COMPOSE_REFERENCE_H__ diff --git a/src/libnr/nr-compose-test.h b/src/libnr/nr-compose-test.h deleted file mode 100644 index 2164e1bf4..000000000 --- a/src/libnr/nr-compose-test.h +++ /dev/null @@ -1,457 +0,0 @@ - -#include <cxxtest/TestSuite.h> - -#include "nr-compose.h" -#include "nr-compose-reference.h" -#include <glib.h> -#include <memory.h> -#include <stdio.h> -#include <stdlib.h> - -static inline unsigned int DIV_ROUND(unsigned int v, unsigned int divisor) { return (v+divisor/2)/divisor; } -static inline unsigned char NR_PREMUL_111(unsigned int c, unsigned int a) { return static_cast<unsigned char>(DIV_ROUND(c*a, 255)); } - -template<PIXEL_FORMAT format> -int IMGCMP(const unsigned char* a, const unsigned char* b, size_t n) { return memcmp(a, b, n); } - -template<> -int IMGCMP<R8G8B8A8N>(const unsigned char* a, const unsigned char* b, size_t n) -{ - // If two pixels each have their alpha channel set to zero they're equivalent - // Note that this doesn't work for premultiplied values, as their color values should - // be zero when alpha is zero. - int cr = 0; - while(n && cr == 0) { - if ( a[3] != 0 || b[3] != 0 ) { - cr = memcmp(a, b, 4); - } - a+=4; - b+=4; - n-=4; - } - return cr; -} - -class NrComposeTest : public CxxTest::TestSuite { -private: - int const w, h; - - unsigned char* const dst_rgba_n_org; - unsigned char* const dst_rgba_p_org; - unsigned char* const dst_rgb_org; - - unsigned char* const dst1_rgba; - unsigned char* const dst2_rgba; - unsigned char* const src_rgba_n; - unsigned char* const src_rgba_p; - unsigned char* const dst1_rgb; - unsigned char* const dst2_rgb; - unsigned char* const src_rgb; - unsigned char* const mask; - - static unsigned int const alpha_vals[7]; - static unsigned int const rgb_vals[3]; - -public: - NrComposeTest() : - w(13), - h(5), - - dst_rgba_n_org(new unsigned char[w*h*4]), - dst_rgba_p_org(new unsigned char[w*h*4]), - dst_rgb_org(new unsigned char[w*h*3]), - - dst1_rgba(new unsigned char[w*h*4]), - dst2_rgba(new unsigned char[w*h*4]), - src_rgba_n(new unsigned char[w*h*4]), - src_rgba_p(new unsigned char[w*h*4]), - dst1_rgb(new unsigned char[w*h*3]), - dst2_rgb(new unsigned char[w*h*3]), - src_rgb(new unsigned char[w*h*3]), - mask(new unsigned char[w*h]) - { - srand(23874683); // It shouldn't really matter what this is, as long as it's always the same (to be reproducible) - - for(int y=0; y<h; y++) { - for(int x=0; x<w; x++) { - dst_rgba_n_org[(x+y*w)*4+3] = 255*rand()/RAND_MAX; - dst_rgba_p_org[(x+y*w)*4+3] = 255*rand()/RAND_MAX; - src_rgba_n[(x+y*w)*4+3] = 255*rand()/RAND_MAX; - src_rgba_p[(x+y*w)*4+3] = 255*rand()/RAND_MAX; - for(int i=0; i<3; i++) { - dst_rgba_n_org[(x+y*w)*4+i] = 255*rand()/RAND_MAX; - dst_rgba_p_org[(x+y*w)*4+i] = NR_PREMUL_111(255*rand()/RAND_MAX, dst_rgba_p_org[(x+y*w)*4+3]); - src_rgba_n[(x+y*w)*4+i] = 255*rand()/RAND_MAX; - src_rgba_p[(x+y*w)*4+i] = NR_PREMUL_111(255*rand()/RAND_MAX, src_rgba_p[(x+y*w)*4+3]); - dst_rgb_org[(x+y*w)*3+i] = 255*rand()/RAND_MAX; - } - mask[x+y*w] = 255*rand()/RAND_MAX; - } - } - } - virtual ~NrComposeTest() - { - delete[] dst_rgba_n_org; - delete[] dst_rgba_p_org; - delete[] dst_rgb_org; - - delete[] dst1_rgba; - delete[] dst2_rgba; - delete[] src_rgba_n; - delete[] src_rgba_p; - delete[] dst1_rgb; - delete[] dst2_rgb; - delete[] src_rgb; - delete[] mask; - } - -// createSuite and destroySuite get us per-suite setup and teardown -// without us having to worry about static initialization order, etc. - static NrComposeTest *createSuite() { return new NrComposeTest(); } - static void destroySuite( NrComposeTest *suite ) { delete suite; } - - // FINAL DST SRC - - void testnr_R8G8B8A8_N_EMPTY_R8G8B8A8_N() - { - for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { - unsigned int alpha = alpha_vals[i]; - char msg[40]; - sprintf(msg, "alpha = %u", alpha); - memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); - nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N(dst1_rgba, w, h, w*4, src_rgba_n, w*4, alpha); - nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, alpha); - TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - } - - void testnr_R8G8B8A8_N_EMPTY_R8G8B8A8_P() - { - for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { - unsigned int alpha = alpha_vals[i]; - char msg[40]; - sprintf(msg, "alpha = %u", alpha); - memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); - nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P(dst1_rgba, w, h, w*4, src_rgba_p, w*4, alpha); - nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, alpha); - TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - } - - void testnr_R8G8B8A8_P_EMPTY_R8G8B8A8_N() - { - for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { - unsigned int alpha = alpha_vals[i]; - char msg[40]; - sprintf(msg, "alpha = %u", alpha); - memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); - nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N(dst1_rgba, w, h, w*4, src_rgba_n, w*4, alpha); - nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, alpha); - TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - } - - void testnr_R8G8B8A8_P_EMPTY_R8G8B8A8_P() - { - for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { - unsigned int alpha = alpha_vals[i]; - char msg[40]; - sprintf(msg, "alpha = %u", alpha); - memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); - nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P(dst1_rgba, w, h, w*4, src_rgba_p, w*4, alpha); - nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, alpha); - TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - } - - void testnr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N() - { - for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { - unsigned int alpha = alpha_vals[i]; - char msg[40]; - sprintf(msg, "alpha = %u", alpha); - memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N(dst1_rgba, w, h, w*4, src_rgba_n, w*4, alpha); - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, alpha); - TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - } - - void testnr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P() - { - for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { - unsigned int alpha = alpha_vals[i]; - char msg[40]; - sprintf(msg, "alpha = %u", alpha); - memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P(dst1_rgba, w, h, w*4, src_rgba_p, w*4, alpha); - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, alpha); - TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - } - - void testnr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N() - { - for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { - unsigned int alpha = alpha_vals[i]; - char msg[40]; - sprintf(msg, "alpha = %u", alpha); - memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N(dst1_rgba, w, h, w*4, src_rgba_n, w*4, alpha); - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, alpha); - TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - } - - void testnr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P() - { - for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { - unsigned int alpha = alpha_vals[i]; - char msg[40]; - sprintf(msg, "alpha = %u", alpha); - memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P(dst1_rgba, w, h, w*4, src_rgba_p, w*4, alpha); - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, alpha); - TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - } - - // FINAL DST SRC MASK - - void testnr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8() - { - memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); - nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8(dst1_rgba, w, h, w*4, src_rgba_n, w*4, mask, w); - nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, mask, w); - TS_ASSERT( IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - - void testnr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8() - { - memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); - nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8(dst1_rgba, w, h, w*4, src_rgba_p, w*4, mask, w); - nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, mask, w); - TS_ASSERT( IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - - void testnr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8() - { - memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); - nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8(dst1_rgba, w, h, w*4, src_rgba_n, w*4, mask, w); - nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, mask, w); - TS_ASSERT( IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - - void testnr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8() - { - memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); - nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8(dst1_rgba, w, h, w*4, src_rgba_p, w*4, mask, w); - nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, mask, w); - TS_ASSERT( IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - - void testnr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8() - { - memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8(dst1_rgba, w, h, w*4, src_rgba_n, w*4, mask, w); - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, mask, w); - TS_ASSERT( IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - - void testnr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8() - { - memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8(dst1_rgba, w, h, w*4, src_rgba_p, w*4, mask, w); - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, mask, w); - TS_ASSERT( IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - - void testnr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8() - { - memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8(dst1_rgba, w, h, w*4, src_rgba_n, w*4, mask, w); - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, mask, w); - TS_ASSERT( IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - - void testnr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8() - { - memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8(dst1_rgba, w, h, w*4, src_rgba_p, w*4, mask, w); - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, mask, w); - TS_ASSERT( IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - - // FINAL DST MASK COLOR - - void testnr_R8G8B8A8_N_EMPTY_A8_RGBA32() - { - for(size_t j=0; j<G_N_ELEMENTS(rgb_vals); j++) { - for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { - unsigned int rgba = rgb_vals[j]+alpha_vals[i]; - char msg[100]; - sprintf(msg, "color = (%u,%u,%u,%u)", (rgba>>24u)&0xff, (rgba>>16u)&0xff, (rgba>>8u)&0xff, rgba&0xff); - memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); - nr_R8G8B8A8_N_EMPTY_A8_RGBA32(dst1_rgba, w, h, w*4, mask, w, rgba); - nr_R8G8B8A8_N_EMPTY_A8_RGBA32_ref(dst2_rgba, w, h, w*4, mask, w, rgba); - TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - } - } - - void testnr_R8G8B8A8_P_EMPTY_A8_RGBA32() - { - for(size_t j=0; j<G_N_ELEMENTS(rgb_vals); j++) { - for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { - unsigned int rgba = rgb_vals[j]+alpha_vals[i]; - char msg[100]; - sprintf(msg, "color = (%u,%u,%u,%u)", (rgba>>24u)&0xff, (rgba>>16u)&0xff, (rgba>>8u)&0xff, rgba&0xff); - memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); - nr_R8G8B8A8_P_EMPTY_A8_RGBA32(dst1_rgba, w, h, w*4, mask, w, rgba); - nr_R8G8B8A8_P_EMPTY_A8_RGBA32_ref(dst2_rgba, w, h, w*4, mask, w, rgba); - TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - } - } - - void testnr_R8G8B8_R8G8B8_A8_RGBA32() - { - for(size_t j=0; j<G_N_ELEMENTS(rgb_vals); j++) { - for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { - unsigned int rgba = rgb_vals[j]+alpha_vals[i]; - char msg[100]; - sprintf(msg, "color = (%u,%u,%u,%u)", (rgba>>24u)&0xff, (rgba>>16u)&0xff, (rgba>>8u)&0xff, rgba&0xff); - memcpy(dst1_rgb, dst_rgb_org, w*h*3); - memcpy(dst2_rgb, dst_rgb_org, w*h*3); - nr_R8G8B8_R8G8B8_A8_RGBA32(dst1_rgb, w, h, w*3, mask, w, rgba); - nr_R8G8B8_R8G8B8_A8_RGBA32_ref(dst2_rgb, w, h, w*3, mask, w, rgba); - TSM_ASSERT(msg, IMGCMP<R8G8B8>(dst1_rgb, dst2_rgb, w*h*3) == 0 ); - } - } - } - - void testnr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32() - { - for(size_t j=0; j<G_N_ELEMENTS(rgb_vals); j++) { - for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { - unsigned int rgba = rgb_vals[j]+alpha_vals[i]; - char msg[100]; - sprintf(msg, "color = (%u,%u,%u,%u)", (rgba>>24u)&0xff, (rgba>>16u)&0xff, (rgba>>8u)&0xff, rgba&0xff); - memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); - nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32(dst1_rgba, w, h, w*4, mask, w, rgba); - nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32_ref(dst2_rgba, w, h, w*4, mask, w, rgba); - TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - } - } - - void testnr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32() - { - for(size_t j=0; j<G_N_ELEMENTS(rgb_vals); j++) { - for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { - unsigned int rgba = rgb_vals[j]+alpha_vals[i]; - char msg[100]; - sprintf(msg, "color = (%u,%u,%u,%u)", (rgba>>24u)&0xff, (rgba>>16u)&0xff, (rgba>>8u)&0xff, rgba&0xff); - memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); - memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); - nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32(dst1_rgba, w, h, w*4, mask, w, rgba); - nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32_ref(dst2_rgba, w, h, w*4, mask, w, rgba); - TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); - } - } - } - - // RGB - - void testnr_R8G8B8_R8G8B8_R8G8B8A8_N() - { - for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { - unsigned int alpha = alpha_vals[i]; - char msg[40]; - sprintf(msg, "alpha = %u", alpha); - memcpy(dst1_rgb, dst_rgb_org, w*h*3); - memcpy(dst2_rgb, dst_rgb_org, w*h*3); - nr_R8G8B8_R8G8B8_R8G8B8A8_N(dst1_rgb, w, h, w*3, src_rgba_n, w*4, alpha); - nr_R8G8B8_R8G8B8_R8G8B8A8_N_ref(dst2_rgb, w, h, w*3, src_rgba_n, w*4, alpha); - TSM_ASSERT(msg, IMGCMP<R8G8B8>(dst1_rgb, dst2_rgb, w*h*3) == 0 ); - } - } - - void testnr_R8G8B8_R8G8B8_R8G8B8A8_P() - { - for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { - unsigned int alpha = alpha_vals[i]; - char msg[40]; - sprintf(msg, "alpha = %u", alpha); - memcpy(dst1_rgb, dst_rgb_org, w*h*3); - memcpy(dst2_rgb, dst_rgb_org, w*h*3); - nr_R8G8B8_R8G8B8_R8G8B8A8_P(dst1_rgb, w, h, w*3, src_rgba_p, w*4, alpha); - nr_R8G8B8_R8G8B8_R8G8B8A8_P_ref(dst2_rgb, w, h, w*3, src_rgba_p, w*4, alpha); - TSM_ASSERT(msg, IMGCMP<R8G8B8>(dst1_rgb, dst2_rgb, w*h*3) == 0 ); - } - } - - void testnr_R8G8B8_R8G8B8_R8G8B8A8_N_A8() - { - for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { - unsigned int alpha = alpha_vals[i]; - char msg[40]; - sprintf(msg, "alpha = %u", alpha); - memcpy(dst1_rgb, dst_rgb_org, w*h*3); - memcpy(dst2_rgb, dst_rgb_org, w*h*3); - nr_R8G8B8_R8G8B8_R8G8B8A8_N_A8(dst1_rgb, w, h, w*3, src_rgba_n, w*4, mask, w); - nr_R8G8B8_R8G8B8_R8G8B8A8_N_A8_ref(dst2_rgb, w, h, w*3, src_rgba_n, w*4, mask, w); - TSM_ASSERT(msg, IMGCMP<R8G8B8>(dst1_rgb, dst2_rgb, w*h*3) == 0 ); - } - } - - void testnr_R8G8B8_R8G8B8_R8G8B8A8_P_A8() - { - for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { - unsigned int alpha = alpha_vals[i]; - char msg[40]; - sprintf(msg, "alpha = %u", alpha); - memcpy(dst1_rgb, dst_rgb_org, w*h*3); - memcpy(dst2_rgb, dst_rgb_org, w*h*3); - nr_R8G8B8_R8G8B8_R8G8B8A8_P_A8(dst1_rgb, w, h, w*3, src_rgba_p, w*4, mask, w); - nr_R8G8B8_R8G8B8_R8G8B8A8_P_A8_ref(dst2_rgb, w, h, w*3, src_rgba_p, w*4, mask, w); - TSM_ASSERT(msg, IMGCMP<R8G8B8>(dst1_rgb, dst2_rgb, w*h*3) == 0 ); - } - } -}; - -unsigned int const NrComposeTest::alpha_vals[7] = {0, 1, 127, 128, 129, 254, 255}; -unsigned int const NrComposeTest::rgb_vals[3] = { - ( 0u<<24u)+( 1u<<16u)+( 92u<<8u), - (127u<<24u)+(128u<<16u)+(129u<<8u), - (163u<<24u)+(254u<<16u)+(255u<<8u)}; - -/* -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 : diff --git a/src/libnr/nr-compose-transform.cpp b/src/libnr/nr-compose-transform.cpp deleted file mode 100644 index 05852bf07..000000000 --- a/src/libnr/nr-compose-transform.cpp +++ /dev/null @@ -1,367 +0,0 @@ -#define __NR_COMPOSE_TRANSFORM_C__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * This code is in public domain - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "nr-pixops.h" -#include "nr-matrix.h" - -/*#ifdef WITH_MMX -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus -/ * fixme: * / -/ *int nr_have_mmx (void); -#define NR_PIXOPS_MMX (1 && nr_have_mmx ()) -#ifdef __cplusplus -} -#endif //__cplusplus -#endif -*/ - -/* fixme: Implement missing (Lauris) */ -/* fixme: PREMUL colors before calculating average (Lauris) */ - -/* Fixed point precision */ -#define FBITS 12 -#define FBITS_HP 18 // In some places we need a higher precision - -void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const NR::Matrix &d2s, unsigned int alpha, int xd, int yd); -void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const NR::Matrix &d2s, unsigned int alpha, int xd, int yd); -void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const NR::Matrix &d2s, unsigned int alpha, int xd, int yd); -void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const NR::Matrix &d2s, unsigned int alpha, int xd, int yd); - -void -nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const NR::Matrix &d2s, unsigned int alpha, int xd, int yd) -{ - int xsize, ysize, size, dbits; - long FFs_x_x, FFs_x_y, FFs_y_x, FFs_y_y, FFs__x, FFs__y; - long FFs_x_x_S, FFs_x_y_S, FFs_y_x_S, FFs_y_y_S; - /* Subpixel positions */ - int FF_sx_S[256]; - int FF_sy_S[256]; - unsigned char *d0; - int FFsx0, FFsy0; - int x, y; - - if (alpha == 0) return; - if (alpha>255) { - g_warning("In transform PPN alpha=%u>255",alpha); - } - - // The color component is stored temporarily with a range of [0,255^3], so more supersampling and we get an overflow (fortunately Inkscape's preferences also doesn't allow a higher setting) - if (xd+yd>8) { - xd = 4; - yd = 4; - } - - xsize = (1 << xd); - ysize = (1 << yd); - size = xsize * ysize; - dbits = xd + yd; - unsigned int rounding_fix = size/2; - - /* Set up fixed point matrix */ - FFs_x_x = (long) floor(d2s[0] * (1 << FBITS) + 0.5); - FFs_x_y = (long) floor(d2s[1] * (1 << FBITS) + 0.5); - FFs_y_x = (long) floor(d2s[2] * (1 << FBITS) + 0.5); - FFs_y_y = (long) floor(d2s[3] * (1 << FBITS) + 0.5); - FFs__x = (long) floor(d2s[4] * (1 << FBITS) + 0.5); - FFs__y = (long) floor(d2s[5] * (1 << FBITS) + 0.5); - - FFs_x_x_S = FFs_x_x >> xd; - FFs_x_y_S = FFs_x_y >> xd; - FFs_y_x_S = FFs_y_x >> yd; - FFs_y_y_S = FFs_y_y >> yd; - - /* Set up subpixel matrix */ - /* fixme: We can calculate that in floating point (Lauris) */ - for (y = 0; y < ysize; y++) { - for (x = 0; x < xsize; x++) { - FF_sx_S[y * xsize + x] = FFs_x_x_S * x + FFs_y_x_S * y; - FF_sy_S[y * xsize + x] = FFs_x_y_S * x + FFs_y_y_S * y; - } - } - - d0 = px; - FFsx0 = FFs__x; - FFsy0 = FFs__y; - - for (y = 0; y < h; y++) { - unsigned char *d; - long FFsx, FFsy; - d = d0; - FFsx = FFsx0; - FFsy = FFsy0; - for (x = 0; x < w; x++) { - unsigned int r, g, b, a; - long sx, sy; - int i; - r = g = b = a = 0; - for (i = 0; i < size; i++) { - sx = (FFsx + FF_sx_S[i]) >> FBITS; - if ((sx >= 0) && (sx < sw)) { - sy = (FFsy + FF_sy_S[i]) >> FBITS; - if ((sy >= 0) && (sy < sh)) { - const unsigned char *s; - s = spx + sy * srs + sx * 4; - r += NR_PREMUL_112 (s[0], s[3]); // s in [0,255] - g += NR_PREMUL_112 (s[1], s[3]); - b += NR_PREMUL_112 (s[2], s[3]); - a += s[3]; - // a=sum(s3) - // r,g,b in [0,sum(s3)*255] - } - } - } - a = (a*alpha + rounding_fix) >> dbits; - // a=sum(s3)*alpha/size=avg(s3)*alpha - // Compare to nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P - if (a != 0) { - r = (r*alpha + rounding_fix) >> dbits; - g = (g*alpha + rounding_fix) >> dbits; - b = (b*alpha + rounding_fix) >> dbits; - // r,g,b in [0,avg(s3)*alpha*255]=[0,a*255] - if (a == 255*255) { - /* Full coverage, demul src */ - d[0] = NR_NORMALIZE_31(r); - d[1] = NR_NORMALIZE_31(g); - d[2] = NR_NORMALIZE_31(b); - d[3] = NR_NORMALIZE_21(a); - } else if (d[3] == 0) { - /* Only foreground, demul src */ - d[0] = NR_DEMUL_321(r,a); - d[1] = NR_DEMUL_321(g,a); - d[2] = NR_DEMUL_321(b,a); - d[3] = NR_NORMALIZE_21(a); - } else { - unsigned int ca; - /* Full composition */ - ca = NR_COMPOSEA_213(a, d[3]); - d[0] = NR_COMPOSEPNN_321131 (r, a, d[0], d[3], ca); - d[1] = NR_COMPOSEPNN_321131 (g, a, d[1], d[3], ca); - d[2] = NR_COMPOSEPNN_321131 (b, a, d[2], d[3], ca); - d[3] = NR_NORMALIZE_31(ca); - } - } - /* Advance pointers */ - FFsx += FFs_x_x; - FFsy += FFs_x_y; - d += 4; - } - FFsx0 += FFs_y_x; - FFsy0 += FFs_y_y; - d0 += rs; - } -} - -void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const NR::Matrix &d2s, unsigned int alpha, int xd, int yd); - -static void -nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const long long *FFd2s, unsigned int alpha) -{ - unsigned char *d0; - long long FFsx0, FFsy0; - int x, y; - - d0 = px; - FFsx0 = FFd2s[4]; - FFsy0 = FFd2s[5]; - - for (y = 0; y < h; y++) { - unsigned char *d; - long long FFsx, FFsy; - d = d0; - FFsx = FFsx0; - FFsy = FFsy0; - for (x = 0; x < w; x++) { - long sx, sy; - sx = long(FFsx >> FBITS_HP); - if ((sx >= 0) && (sx < sw)) { - sy = long(FFsy >> FBITS_HP); - if ((sy >= 0) && (sy < sh)) { - const unsigned char *s; - unsigned int a; - s = spx + sy * srs + sx * 4; - a = NR_PREMUL_112 (s[3], alpha); - if (a != 0) { - if ((a == 255*255) || (d[3] == 0)) { - /* Transparent BG, premul src */ - d[0] = NR_PREMUL_121 (s[0], a); - d[1] = NR_PREMUL_121 (s[1], a); - d[2] = NR_PREMUL_121 (s[2], a); - d[3] = NR_NORMALIZE_21(a); - } else { - d[0] = NR_COMPOSENPP_1211 (s[0], a, d[0]); - d[1] = NR_COMPOSENPP_1211 (s[1], a, d[1]); - d[2] = NR_COMPOSENPP_1211 (s[2], a, d[2]); - d[3] = NR_COMPOSEA_211(a, d[3]); - } - } - } - } - /* Advance pointers */ - FFsx += FFd2s[0]; - FFsy += FFd2s[1]; - d += 4; - } - FFsx0 += FFd2s[2]; - FFsy0 += FFd2s[3]; - d0 += rs; - } -} - -static void -nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const long long *FFd2s, const long *FF_S, unsigned int alpha, int dbits) -{ - int size; - unsigned char *d0; - long long FFsx0, FFsy0; - int x, y; - - size = (1 << dbits); - unsigned int rounding_fix = size/2; - - d0 = px; - FFsx0 = FFd2s[4]; - FFsy0 = FFd2s[5]; - - for (y = 0; y < h; y++) { - unsigned char *d; - long long FFsx, FFsy; - d = d0; - FFsx = FFsx0; - FFsy = FFsy0; - for (x = 0; x < w; x++) { - unsigned int r, g, b, a; - int i; - r = g = b = a = 0; - for (i = 0; i < size; i++) { - long sx, sy; - sx = (long (FFsx >> (FBITS_HP - FBITS)) + FF_S[2 * i]) >> FBITS; - if ((sx >= 0) && (sx < sw)) { - sy = (long (FFsy >> (FBITS_HP - FBITS)) + FF_S[2 * i + 1]) >> FBITS; - if ((sy >= 0) && (sy < sh)) { - const unsigned char *s; - s = spx + sy * srs + sx * 4; - r += NR_PREMUL_112(s[0], s[3]); - g += NR_PREMUL_112(s[1], s[3]); - b += NR_PREMUL_112(s[2], s[3]); - a += s[3]; - } - } - } - a = (a*alpha + rounding_fix) >> dbits; - if (a != 0) { - r = (r*alpha + rounding_fix) >> dbits; - g = (g*alpha + rounding_fix) >> dbits; - b = (b*alpha + rounding_fix) >> dbits; - if ((a == 255*255) || (d[3] == 0)) { - /* Transparent BG, premul src */ - d[0] = NR_NORMALIZE_31(r); - d[1] = NR_NORMALIZE_31(g); - d[2] = NR_NORMALIZE_31(b); - d[3] = NR_NORMALIZE_21(a); - } else { - d[0] = NR_COMPOSEPPP_3211 (r, a, d[0]); - d[1] = NR_COMPOSEPPP_3211 (g, a, d[1]); - d[2] = NR_COMPOSEPPP_3211 (b, a, d[2]); - d[3] = NR_COMPOSEA_211(a, d[3]); - } - } - /* Advance pointers */ - FFsx += FFd2s[0]; - FFsy += FFd2s[1]; - d += 4; - } - FFsx0 += FFd2s[2]; - FFsy0 += FFd2s[3]; - d0 += rs; - } -} - -void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const NR::Matrix &d2s, unsigned int alpha, int xd, int yd) -{ - int dbits; - long FFd2s[6]; - long long FFd2s_HP[6]; // with higher precision - int i; - - if (alpha == 0) return; - if (alpha>255) { - g_warning("In transform PPN alpha=%u>255",alpha); - } - - // The color component is stored temporarily with a range of [0,255^3], so more supersampling and we get an overflow (fortunately Inkscape's preferences also doesn't allow a higher setting) - if (xd+yd>8) { - xd = 4; - yd = 4; - } - - dbits = xd + yd; - - for (i = 0; i < 6; i++) { - FFd2s[i] = (long) floor(d2s[i] * (1 << FBITS) + 0.5); - FFd2s_HP[i] = (long long) floor(d2s[i] * (1 << FBITS_HP) + 0.5);; - } - - if (dbits == 0) { - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (px, w, h, rs, spx, sw, sh, srs, FFd2s_HP, alpha); - } else { - int xsize, ysize; - long FFs_x_x_S, FFs_x_y_S, FFs_y_x_S, FFs_y_y_S; - long FF_S[2 * 256]; - int x, y; - - xsize = (1 << xd); - ysize = (1 << yd); - - FFs_x_x_S = FFd2s[0] >> xd; - FFs_x_y_S = FFd2s[1] >> xd; - FFs_y_x_S = FFd2s[2] >> yd; - FFs_y_y_S = FFd2s[3] >> yd; - - /* Set up subpixel matrix */ - /* fixme: We can calculate that in floating point (Lauris) */ - for (y = 0; y < ysize; y++) { - for (x = 0; x < xsize; x++) { - FF_S[2 * (y * xsize + x)] = FFs_x_x_S * x + FFs_y_x_S * y; - FF_S[2 * (y * xsize + x) + 1] = FFs_x_y_S * x + FFs_y_y_S * y; - } - } - - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (px, w, h, rs, spx, sw, sh, srs, FFd2s_HP, FF_S, alpha, dbits); - } -} - -void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const NR::Matrix &d2s, unsigned int alpha, int xd, int yd); diff --git a/src/libnr/nr-compose-transform.h b/src/libnr/nr-compose-transform.h deleted file mode 100644 index 7ffb20074..000000000 --- a/src/libnr/nr-compose-transform.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef __NR_COMPOSE_TRANSFORM_H__ -#define __NR_COMPOSE_TRANSFORM_H__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * This code is in public domain - */ - -#include <libnr/nr-forward.h> - -/* FINAL DST SRC */ - -void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const NR::Matrix &d2s, unsigned int alpha, int xd, int yd); -void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const NR::Matrix &d2s, unsigned int alpha, int xd, int yd); -void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const NR::Matrix &d2s, unsigned int alpha, int xd, int yd); -void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const NR::Matrix &d2s, unsigned int alpha, int xd, int yd); - -void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const NR::Matrix &d2s, unsigned int alpha, int xd, int yd); -void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const NR::Matrix &d2s, unsigned int alpha, int xd, int yd); -void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const NR::Matrix &d2s, unsigned int alpha, int xd, int yd); -void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int sw, int sh, int srs, - const NR::Matrix &d2s, unsigned int alpha, int xd, int yd); - -#endif diff --git a/src/libnr/nr-compose.cpp b/src/libnr/nr-compose.cpp deleted file mode 100644 index 74f9d036b..000000000 --- a/src/libnr/nr-compose.cpp +++ /dev/null @@ -1,1197 +0,0 @@ -#define __NR_COMPOSE_C__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * This code is in public domain - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <string.h> -#include "nr-pixops.h" - -#ifdef WITH_MMX -/* fixme: */ -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ -int nr_have_mmx (void); -void nr_mmx_R8G8B8A8_P_EMPTY_A8_RGBAP (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned char *c); -void nr_mmx_R8G8B8A8_P_R8G8B8A8_P_A8_RGBAP (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned char *c); -void nr_mmx_R8G8B8_R8G8B8_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); -#define NR_PIXOPS_MMX nr_have_mmx () -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif - -// Naming: nr_RESULT_BACKGROUND_FOREGROUND_extra - -void -nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) -{ - unsigned int r, c; - - for (r = h; r > 0; r--) { - if (alpha == 0) { - memset(px, 0x0, 4 * w); - } else if (alpha == 255) { - memcpy(px, spx, 4 * w); - } else { - unsigned char *d = px; - const unsigned char *s = spx; - for (c = w; c > 0; c--) { - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = NR_PREMUL_111(*s, alpha); - s++; - } - } - px += rs; - spx += srs; - } -} - -void -nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) -{ - unsigned int r, c; - - for (r = h; r > 0; r--) { - if (alpha == 0) { - memset(px, 0x0, 4 * w); - } else { - unsigned char *d = px; - const unsigned char *s = spx; - for (c = w; c > 0; c--) { - if (s[3] == 0) { - d[3] = 0; - } else if (s[3] == 255) { - memcpy(d, s, 4); - } else { - d[0] = NR_DEMUL_111(s[0], s[3]); - d[1] = NR_DEMUL_111(s[1], s[3]); - d[2] = NR_DEMUL_111(s[2], s[3]); - d[3] = NR_PREMUL_111(s[3], alpha); - } - d += 4; - s += 4; - } - } - px += rs; - spx += srs; - } -} - -void -nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) -{ - unsigned int r, c; - - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - if (alpha == 0) { - memset(px, 0x0, 4 * w); - } else if (alpha == 255) { - for (c = w; c > 0; c--) { - d[0] = NR_PREMUL_111(s[0], s[3]); - d[1] = NR_PREMUL_111(s[1], s[3]); - d[2] = NR_PREMUL_111(s[2], s[3]); - d[3] = s[3]; - d += 4; - s += 4; - } - } else { - for (c = w; c > 0; c--) { - if (s[3] == 0) { - memset(d, 0, 4); - } else { - unsigned int a; - a = NR_PREMUL_112(s[3], alpha); - d[0] = NR_PREMUL_121(s[0], a); - d[1] = NR_PREMUL_121(s[1], a); - d[2] = NR_PREMUL_121(s[2], a); - d[3] = NR_NORMALIZE_21(a); - } - d += 4; - s += 4; - } - } - px += rs; - spx += srs; - } -} - -void -nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) -{ - unsigned int r, c; - - for (r = h; r > 0; r--) { - if (alpha == 0) { - memset(px, 0x0, 4 * w); - } else if (alpha == 255) { - memcpy(px, spx, 4 * w); - } else { - unsigned char *d = px; - const unsigned char *s = spx; - for (c = w; c > 0; c--) { - d[0] = NR_PREMUL_111(s[0], alpha); - d[1] = NR_PREMUL_111(s[1], alpha); - d[2] = NR_PREMUL_111(s[2], alpha); - d[3] = NR_PREMUL_111(s[3], alpha); - d += 4; - s += 4; - } - } - px += rs; - spx += srs; - } -} - -void -nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) -{ - unsigned int r, c; - - if (alpha == 0) { - /* NOP */ - } else if (alpha == 255) { - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - for (c = w; c > 0; c--) { - if (s[3] == 0) { - /* Transparent FG, NOP */ - } else if ((s[3] == 255) || (d[3] == 0)) { - /* Full coverage, COPY */ - memcpy(d, s, 4); - } else { - /* Full composition */ - unsigned int ca; - ca = NR_COMPOSEA_112(s[3], d[3]); - d[0] = NR_COMPOSENNN_111121(s[0], s[3], d[0], d[3], ca); - d[1] = NR_COMPOSENNN_111121(s[1], s[3], d[1], d[3], ca); - d[2] = NR_COMPOSENNN_111121(s[2], s[3], d[2], d[3], ca); - d[3] = NR_NORMALIZE_21(ca); - } - d += 4; - s += 4; - } - px += rs; - spx += srs; - } - } else { - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - for (c = w; c > 0; c--) { - unsigned int a; - a = NR_PREMUL_112(s[3], alpha); - if (a == 0) { - /* Transparent FG, NOP */ - } else if ((a == 255*255) || (d[3] == 0)) { - /* Full coverage, COPY */ - d[0] = s[0]; - d[1] = s[1]; - d[2] = s[2]; - d[3] = NR_NORMALIZE_21(a); - } else { - /* Full composition */ - unsigned int ca; - ca = NR_COMPOSEA_213(a, d[3]); - d[0] = NR_COMPOSENNN_121131(s[0], a, d[0], d[3], ca); - d[1] = NR_COMPOSENNN_121131(s[1], a, d[1], d[3], ca); - d[2] = NR_COMPOSENNN_121131(s[2], a, d[2], d[3], ca); - d[3] = NR_NORMALIZE_31(ca); - } - d += 4; - s += 4; - } - px += rs; - spx += srs; - } - } -} - -void -nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) -{ - unsigned int r, c; - - if (alpha == 0) { - /* NOP */ - } else if (alpha == 255) { - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - for (c = w; c > 0; c--) { - if (s[3] == 0) { - /* Transparent FG, NOP */ - } else if (s[3] == 255) { - /* Full coverage, demul src */ - // dc' = ((1 - sa) * da*dc + sc)/da' = sc/da' = sc - // da' = 1 - (1 - sa) * (1 - da) = 1 - 0 * (1 - da) = 1 - memcpy(d, s, 4); - } else if (d[3] == 0) { - /* Full coverage, demul src */ - // dc' = ((1 - sa) * da*dc + sc)/da' = sc/da' = sc/sa = sc/sa - // da' = 1 - (1 - sa) * (1 - da) = 1 - (1 - sa) = sa - d[0] = NR_DEMUL_111(s[0], s[3]); - d[1] = NR_DEMUL_111(s[1], s[3]); - d[2] = NR_DEMUL_111(s[2], s[3]); - d[3] = s[3]; - } else { - /* Full composition */ - // dc' = ((1 - sa) * da*dc + sc)/da' = ((1 - sa) * da*dc + sc)/da' - // da' = 1 - (1 - sa) * (1 - da) = 1 - (1 - sa) * (1 - da) - unsigned int da = NR_COMPOSEA_112(s[3], d[3]); - d[0] = NR_COMPOSEPNN_111121(s[0], s[3], d[0], d[3], da); - d[1] = NR_COMPOSEPNN_111121(s[1], s[3], d[1], d[3], da); - d[2] = NR_COMPOSEPNN_111121(s[2], s[3], d[2], d[3], da); - d[3] = NR_NORMALIZE_21(da); - } - d += 4; - s += 4; - } - px += rs; - spx += srs; - } - } else { - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - for (c = w; c > 0; c--) { - unsigned int a; - a = NR_PREMUL_112(s[3], alpha); - if (a == 0) { - /* Transparent FG, NOP */ - } else if (d[3] == 0) { - /* Full coverage, demul src */ - // dc' = ((1 - alpha*sa) * da*dc + alpha*sc)/da' = alpha*sc/da' = alpha*sc/(alpha*sa) = sc/sa - // da' = 1 - (1 - alpha*sa) * (1 - da) = 1 - (1 - alpha*sa) = alpha*sa - d[0] = NR_DEMUL_111(s[0], s[3]); - d[1] = NR_DEMUL_111(s[1], s[3]); - d[2] = NR_DEMUL_111(s[2], s[3]); - d[3] = NR_NORMALIZE_21(a); - } else { - // dc' = ((1 - alpha*sa) * da*dc + alpha*sc)/da' - // da' = 1 - (1 - alpha*sa) * (1 - da) - unsigned int da = NR_COMPOSEA_213(a, d[3]); - d[0] = NR_COMPOSEPNN_221131(NR_PREMUL_112(s[0], alpha), a, d[0], d[3], da); - d[1] = NR_COMPOSEPNN_221131(NR_PREMUL_112(s[1], alpha), a, d[1], d[3], da); - d[2] = NR_COMPOSEPNN_221131(NR_PREMUL_112(s[2], alpha), a, d[2], d[3], da); - d[3] = NR_NORMALIZE_31(da); - } - d += 4; - s += 4; - } - px += rs; - spx += srs; - } - } -} - -void -nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) -{ - unsigned int r, c; - - if (alpha == 0) { - /* NOP */ - } else if (alpha == 255) { - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - for (c = w; c > 0; c--) { - if (s[3] == 0) { - /* Transparent FG, NOP */ - } else if (s[3] == 255) { - /* Opaque FG, COPY */ - // dc' = (1 - sa) * dc + sa*sc = sa*sc = sc - // da' = 1 - (1 - sa) * (1 - da) = 1 - 0 * (1 - da) = 1 (= sa) - memcpy(d, s, 4); - } else if (d[3] == 0) { - /* Transparent BG, premul src */ - // dc' = (1 - sa) * dc + sa*sc = sa*sc - // da' = 1 - (1 - sa) * (1 - da) = 1 - (1 - sa) = sa - d[0] = NR_PREMUL_111(s[0], s[3]); - d[1] = NR_PREMUL_111(s[1], s[3]); - d[2] = NR_PREMUL_111(s[2], s[3]); - d[3] = s[3]; - } else { - // dc' = (1 - sa) * dc + sa*sc - // da' = 1 - (1 - sa) * (1 - da) - d[0] = NR_COMPOSENPP_1111(s[0], s[3], d[0]); - d[1] = NR_COMPOSENPP_1111(s[1], s[3], d[1]); - d[2] = NR_COMPOSENPP_1111(s[2], s[3], d[2]); - d[3] = NR_COMPOSEA_111(s[3], d[3]); - } - d += 4; - s += 4; - } - px += rs; - spx += srs; - } - } else { - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - for (c = w; c > 0; c--) { - unsigned int a; - a = NR_PREMUL_112 (s[3], alpha); - if (a == 0) { - /* Transparent FG, NOP */ - } else if (d[3] == 0) { - /* Transparent BG, premul src */ - // dc' = (1 - alpha*sa) * dc + alpha*sa*sc = alpha*sa*sc - // da' = 1 - (1 - alpha*sa) * (1 - da) = 1 - (1 - alpha*sa) = alpha*sa - d[0] = NR_PREMUL_121(s[0], a); - d[1] = NR_PREMUL_121(s[1], a); - d[2] = NR_PREMUL_121(s[2], a); - d[3] = NR_NORMALIZE_21(a); - } else { - // dc' = (1 - alpha*sa) * dc + alpha*sa*sc - // da' = 1 - (1 - alpha*sa) * (1 - da) - d[0] = NR_COMPOSENPP_1211(s[0], a, d[0]); - d[1] = NR_COMPOSENPP_1211(s[1], a, d[1]); - d[2] = NR_COMPOSENPP_1211(s[2], a, d[2]); - d[3] = NR_COMPOSEA_211(a, d[3]); - } - d += 4; - s += 4; - } - px += rs; - spx += srs; - } - } -} - -void -nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) -{ - unsigned int r, c; - - if (alpha == 0) { - /* Transparent FG, NOP */ - } else if (alpha == 255) { - /* Simple */ - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - for (c = w; c > 0; c--) { - if (s[3] == 0) { - /* Transparent FG, NOP */ - } else if ((s[3] == 255) || (d[3] == 0)) { - /* Transparent BG, COPY */ - memcpy(d, s, 4); - } else { - d[0] = NR_COMPOSEPPP_1111(s[0], s[3], d[0]); - d[1] = NR_COMPOSEPPP_1111(s[1], s[3], d[1]); - d[2] = NR_COMPOSEPPP_1111(s[2], s[3], d[2]); - d[3] = NR_COMPOSEA_111(s[3], d[3]); - } - d += 4; - s += 4; - } - px += rs; - spx += srs; - } - } else { - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - for (c = w; c > 0; c--) { - if (s[3] == 0) { - /* Transparent FG, NOP */ - } else if (d[3] == 0) { - /* Transparent BG, COPY */ - d[0] = NR_PREMUL_111(s[0], alpha); - d[1] = NR_PREMUL_111(s[1], alpha); - d[2] = NR_PREMUL_111(s[2], alpha); - d[3] = NR_PREMUL_111(s[3], alpha); - } else { - // dc' = (1 - alpha*sa) * dc + alpha*sc - // da' = 1 - (1 - alpha*sa) * (1 - da) - unsigned int a; - a = NR_PREMUL_112(s[3], alpha); - d[0] = NR_COMPOSEPPP_2211(NR_PREMUL_112(alpha, s[0]), a, d[0]); - d[1] = NR_COMPOSEPPP_2211(NR_PREMUL_112(alpha, s[1]), a, d[1]); - d[2] = NR_COMPOSEPPP_2211(NR_PREMUL_112(alpha, s[2]), a, d[2]); - d[3] = NR_COMPOSEA_211(a, d[3]); - } - d += 4; - s += 4; - } - px += rs; - spx += srs; - } - } -} - -/* Masked operations */ - -void -nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) -{ - unsigned int r, c; - - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - const unsigned char *m = mpx; - for (c = w; c > 0; c--) { - d[0] = s[0]; - d[1] = s[1]; - d[2] = s[2]; - d[3] = NR_PREMUL_111(s[3], m[0]); - d += 4; - s += 4; - m += 1; - } - px += rs; - spx += srs; - mpx += mrs; - } -} - -void -nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) -{ - unsigned int r, c; - - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - const unsigned char *m = mpx; - for (c = w; c > 0; c--) { - unsigned int a; - a = NR_PREMUL_112 (s[3], m[0]); - if (a == 0) { - d[3] = 0; - } else if (a == 255*255) { - memcpy(d, s, 4); - } else { - // dc' = ((1 - m*sa) * da*dc + m*sc)/da' = m*sc/da' = m*sc/(m*sa) = sc/sa - // da' = 1 - (1 - m*sa) * (1 - da) = 1 - (1 - m*sa) = m*sa - d[0] = NR_DEMUL_111(s[0], s[3]); - d[1] = NR_DEMUL_111(s[1], s[3]); - d[2] = NR_DEMUL_111(s[2], s[3]); - d[3] = NR_NORMALIZE_21(a); - } - d += 4; - s += 4; - m += 1; - } - px += rs; - spx += srs; - mpx += mrs; - } -} - -void -nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) -{ - unsigned int r, c; - - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - const unsigned char *m = mpx; - for (c = w; c > 0; c--) { - unsigned int a; - a = NR_PREMUL_112(s[3], m[0]); - if (a == 0) { - memset(d, 0, 4); - } else if (a == 255*255) { - memcpy(d, s, 4); - } else { - d[0] = NR_PREMUL_121(s[0], a); - d[1] = NR_PREMUL_121(s[1], a); - d[2] = NR_PREMUL_121(s[2], a); - d[3] = NR_NORMALIZE_21(a); - } - d += 4; - s += 4; - m += 1; - } - px += rs; - spx += srs; - mpx += mrs; - } -} - -void -nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) -{ - unsigned int r, c; - - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - const unsigned char *m = mpx; - for (c = w; c > 0; c--) { - d[0] = NR_PREMUL_111(s[0], m[0]); - d[1] = NR_PREMUL_111(s[1], m[0]); - d[2] = NR_PREMUL_111(s[2], m[0]); - d[3] = NR_PREMUL_111(s[3], m[0]); - d += 4; - s += 4; - m += 1; - } - px += rs; - spx += srs; - mpx += mrs; - } -} - -void -nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) -{ - unsigned int r, c; - - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - const unsigned char *m = mpx; - for (c = w; c > 0; c--) { - unsigned int a; - a = NR_PREMUL_112(s[3], m[0]); - if (a == 0) { - /* Transparent FG, NOP */ - } else if ((a == 255*255) || (d[3] == 0)) { - /* Full coverage, COPY */ - d[0] = s[0]; - d[1] = s[1]; - d[2] = s[2]; - d[3] = NR_NORMALIZE_21(a); - } else { - /* Full composition */ - unsigned int ca; - ca = NR_COMPOSEA_213(a, d[3]); - d[0] = NR_COMPOSENNN_121131(s[0], a, d[0], d[3], ca); - d[1] = NR_COMPOSENNN_121131(s[1], a, d[1], d[3], ca); - d[2] = NR_COMPOSENNN_121131(s[2], a, d[2], d[3], ca); - d[3] = NR_NORMALIZE_31(ca); - } - d += 4; - s += 4; - m += 1; - } - px += rs; - spx += srs; - mpx += mrs; - } -} - -void -nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) -{ - unsigned int r, c; - - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - const unsigned char *m = mpx; - for (c = w; c > 0; c--) { - unsigned int a; - a = NR_PREMUL_112(s[3], m[0]); - if (a == 0) { - /* Transparent FG, NOP */ - } else if (a == 255*255) { - /* Opaque FG, COPY */ - memcpy(d, s, 4); - } else if (d[3] == 0) { - /* Full coverage, demul src */ - // dc' = ((1 - m*sa) * da*dc + m*sc)/da' = m*sc/da' = m*sc/(m*sa) = sc/sa - // da' = 1 - (1 - m*sa) * (1 - da) = 1 - (1 - m*sa) = m*sa - d[0] = NR_DEMUL_111(s[0], s[3]); - d[1] = NR_DEMUL_111(s[1], s[3]); - d[2] = NR_DEMUL_111(s[2], s[3]); - d[3] = NR_NORMALIZE_21(a); - } else if (m[0] == 255) { - /* Full composition */ - // dc' = ((1 - m*sa) * da*dc + m*sc)/da' = ((1 - sa) * da*dc + sc)/da' - // da' = 1 - (1 - m*sa) * (1 - da) = 1 - (1 - sa) * (1 - da) - unsigned int da = NR_COMPOSEA_112(s[3], d[3]); - d[0] = NR_COMPOSEPNN_111121(s[0], s[3], d[0], d[3], da); - d[1] = NR_COMPOSEPNN_111121(s[1], s[3], d[1], d[3], da); - d[2] = NR_COMPOSEPNN_111121(s[2], s[3], d[2], d[3], da); - d[3] = NR_NORMALIZE_21(da); - } else { - // dc' = ((1 - m*sa) * da*dc + m*sc)/da' - // da' = 1 - (1 - m*sa) * (1 - da) - unsigned int da = NR_COMPOSEA_213(a, d[3]); - d[0] = NR_COMPOSEPNN_221131(NR_PREMUL_112(s[0], m[0]), a, d[0], d[3], da); - d[1] = NR_COMPOSEPNN_221131(NR_PREMUL_112(s[1], m[0]), a, d[1], d[3], da); - d[2] = NR_COMPOSEPNN_221131(NR_PREMUL_112(s[2], m[0]), a, d[2], d[3], da); - d[3] = NR_NORMALIZE_31(da); - } - d += 4; - s += 4; - m += 1; - } - px += rs; - spx += srs; - mpx += mrs; - } -} - -void -nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) -{ - unsigned int r, c; - - for (r = h; r>0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - const unsigned char *m = mpx; - for (c = w; c>0; c--) { - unsigned int a; - a = NR_PREMUL_112(s[3], m[0]); - if (a == 0) { - /* Transparent FG, NOP */ - } else if (a == 255*255) { - memcpy(d, s, 4); - } else { - d[0] = NR_COMPOSENPP_1211(s[0], a, d[0]); - d[1] = NR_COMPOSENPP_1211(s[1], a, d[1]); - d[2] = NR_COMPOSENPP_1211(s[2], a, d[2]); - d[3] = NR_COMPOSEA_211(a, d[3]); - } - d += 4; - s += 4; - m += 1; - } - px += rs; - spx += srs; - mpx += mrs; - } -} - -void -nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) -{ - unsigned int r, c; - - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - const unsigned char *m = mpx; - for (c = w; c > 0; c--) { - unsigned int a; - a = NR_PREMUL_112 (s[3], m[0]); - if (a == 0) { - /* Transparent FG, NOP */ - } else if (a == 255*255) { - /* Opaque FG, COPY */ - memcpy(d, s, 4); - } else if (d[3] == 0) { - /* Transparent BG, COPY */ - // dc' = (1 - m*sa) * dc + m*sc = m*sc - // da' = 1 - (1 - m*sa) * (1 - da) = 1 - (1 - m*sa) = m*sa - d[0] = NR_PREMUL_111 (s[0], m[0]); - d[1] = NR_PREMUL_111 (s[1], m[0]); - d[2] = NR_PREMUL_111 (s[2], m[0]); - d[3] = NR_NORMALIZE_21(a); - } else { - // dc' = (1 - m*sa) * dc + m*sc - // da' = 1 - (1 - m*sa) * (1 - da) - d[0] = NR_COMPOSEPPP_2211 (NR_PREMUL_112 (s[0], m[0]), a, d[0]); - d[1] = NR_COMPOSEPPP_2211 (NR_PREMUL_112 (s[1], m[0]), a, d[1]); - d[2] = NR_COMPOSEPPP_2211 (NR_PREMUL_112 (s[2], m[0]), a, d[2]); - d[3] = NR_COMPOSEA_211(a, d[3]); - } - d += 4; - s += 4; - m += 1; - } - px += rs; - spx += srs; - mpx += mrs; - } -} - -/* FINAL DST MASK COLOR */ - -void -nr_R8G8B8A8_N_EMPTY_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba) -{ - unsigned int r, g, b, a; - unsigned int x, y; - - r = NR_RGBA32_R (rgba); - g = NR_RGBA32_G (rgba); - b = NR_RGBA32_B (rgba); - a = NR_RGBA32_A (rgba); - - for (y = h; y > 0; y--) { - if (a == 0) { - memset(px, 0, w*4); - } else { - unsigned char *d = px; - const unsigned char *m = mpx; - for (x = w; x > 0; x--) { - d[0] = r; - d[1] = g; - d[2] = b; - d[3] = NR_PREMUL_111 (m[0], a); - d += 4; - m += 1; - } - } - px += rs; - mpx += mrs; - } -} - -void -nr_R8G8B8A8_P_EMPTY_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba) -{ - unsigned int r, g, b, a; - unsigned int x, y; - - r = NR_RGBA32_R (rgba); - g = NR_RGBA32_G (rgba); - b = NR_RGBA32_B (rgba); - a = NR_RGBA32_A (rgba); - -#ifdef WITH_MMX - if (NR_PIXOPS_MMX) { - unsigned char c[4]; - c[0] = NR_PREMUL_111 (r, a); - c[1] = NR_PREMUL_111 (g, a); - c[2] = NR_PREMUL_111 (b, a); - c[3] = a; - /* WARNING: MMX composer REQUIRES w > 0 and h > 0 */ - nr_mmx_R8G8B8A8_P_EMPTY_A8_RGBAP (px, w, h, rs, mpx, mrs, c); - // This mmx optimized code is approx. 2x faster than the non-optimized code below (Measured by Diederik van Lierop, 2009-12-17) - return; - } -#endif - - if ( a != 255 ){ - // Pre-premultiply color values - r *= a; - g *= a; - b *= a; - } - - for (y = h; y > 0; y--) { - unsigned char *d = px; - const unsigned char *m = mpx; - if (a == 0) { - memset(px, 0, w*4); - } else if (a == 255) { - for (x = w; x > 0; x--) { - d[0] = NR_PREMUL_111(m[0], r); - d[1] = NR_PREMUL_111(m[0], g); - d[2] = NR_PREMUL_111(m[0], b); - d[3] = m[0]; - d += 4; - m += 1; - } - } else { - for (x = w; x > 0; x--) { - // Color values are already premultiplied with a - d[0] = NR_PREMUL_121(m[0], r); - d[1] = NR_PREMUL_121(m[0], g); - d[2] = NR_PREMUL_121(m[0], b); - d[3] = NR_PREMUL_111(m[0], a); - d += 4; - m += 1; - } - } - px += rs; - mpx += mrs; - } -} - -void -nr_R8G8B8_R8G8B8_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba) -{ - unsigned int r, g, b, a; - unsigned int x, y; - - r = NR_RGBA32_R (rgba); - g = NR_RGBA32_G (rgba); - b = NR_RGBA32_B (rgba); - a = NR_RGBA32_A (rgba); - - if (a == 0) { - /* NOP */ - } else if (a == 255) { - for (y = h; y > 0; y--) { - unsigned char *d = px; - const unsigned char *m = mpx; - for (x = w; x > 0; x--) { - d[0] = NR_COMPOSEN11_1111 (r, m[0], d[0]); - d[1] = NR_COMPOSEN11_1111 (g, m[0], d[1]); - d[2] = NR_COMPOSEN11_1111 (b, m[0], d[2]); - d += 3; - m += 1; - } - px += rs; - mpx += mrs; - } - } else { - for (y = h; y > 0; y--) { - unsigned char *d = px; - const unsigned char *m = mpx; - for (x = w; x > 0; x--) { - // dc' = (1 - m*sa) * dc + m*sa*sc - unsigned int alpha; - alpha = NR_PREMUL_112 (a, m[0]); - d[0] = NR_COMPOSEN11_1211 (r, alpha, d[0]); - d[1] = NR_COMPOSEN11_1211 (g, alpha, d[1]); - d[2] = NR_COMPOSEN11_1211 (b, alpha, d[2]); - d += 3; - m += 1; - } - px += rs; - mpx += mrs; - } - } -} - -void -nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba) -{ - unsigned int r, g, b, a; - unsigned int x, y; - - r = NR_RGBA32_R (rgba); - g = NR_RGBA32_G (rgba); - b = NR_RGBA32_B (rgba); - a = NR_RGBA32_A (rgba); - - if (a == 0) { - /* NOP */ - } else if (a == 255) { - for (y = h; y > 0; y--) { - unsigned char *d = px; - const unsigned char *m = mpx; - for (x = w; x > 0; x--) { - if (m[0] == 0) { - /* Transparent FG, NOP */ - } else if (m[0] == 255 || d[3] == 0) { - /* Full coverage, COPY */ - d[0] = r; - d[1] = g; - d[2] = b; - d[3] = m[0]; - } else { - /* Full composition */ - unsigned int da = NR_COMPOSEA_112(m[0], d[3]); - d[0] = NR_COMPOSENNN_111121(r, m[0], d[0], d[3], da); - d[1] = NR_COMPOSENNN_111121(g, m[0], d[1], d[3], da); - d[2] = NR_COMPOSENNN_111121(b, m[0], d[2], d[3], da); - d[3] = NR_NORMALIZE_21(da); - } - d += 4; - m += 1; - } - px += rs; - mpx += mrs; - } - } else { - for (y = h; y > 0; y--) { - unsigned char *d = px; - const unsigned char *m = mpx; - for (x = w; x > 0; x--) { - unsigned int ca; - ca = NR_PREMUL_112 (m[0], a); - if (ca == 0) { - /* Transparent FG, NOP */ - } else if (d[3] == 0) { - /* Full coverage, COPY */ - d[0] = r; - d[1] = g; - d[2] = b; - d[3] = NR_NORMALIZE_21(ca); - } else { - /* Full composition */ - unsigned int da = NR_COMPOSEA_213(ca, d[3]); - d[0] = NR_COMPOSENNN_121131(r, ca, d[0], d[3], da); - d[1] = NR_COMPOSENNN_121131(g, ca, d[1], d[3], da); - d[2] = NR_COMPOSENNN_121131(b, ca, d[2], d[3], da); - d[3] = NR_NORMALIZE_31(da); - } - d += 4; - m += 1; - } - px += rs; - mpx += mrs; - } - } -} - -void -nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba) -{ - unsigned int r, g, b, a; - unsigned int x, y; - - r = NR_RGBA32_R (rgba); - g = NR_RGBA32_G (rgba); - b = NR_RGBA32_B (rgba); - a = NR_RGBA32_A (rgba); - -#ifdef WITH_MMX - if (NR_PIXOPS_MMX && a != 0) { - unsigned char c[4]; - c[0] = NR_PREMUL_111 (r, a); - c[1] = NR_PREMUL_111 (g, a); - c[2] = NR_PREMUL_111 (b, a); - c[3] = a; - /* WARNING: MMX composer REQUIRES w > 0 and h > 0 */ - nr_mmx_R8G8B8A8_P_R8G8B8A8_P_A8_RGBAP (px, w, h, rs, spx, srs, c); - return; - } -#endif - - if (a == 0) { - /* Transparent FG, NOP */ - } else if (a == 255) { - /* Simple */ - for (y = h; y > 0; y--) { - unsigned char *d, *s; - d = (unsigned char *) px; - s = (unsigned char *) spx; - for (x = w; x > 0; x--) { - if (s[0] == 0) { - /* Transparent FG, NOP */ - } else { - /* Full composition */ - unsigned int invca = 255-s[0]; // By swapping the arguments GCC can better optimize these calls - d[0] = NR_COMPOSENPP_1111(d[0], invca, r); - d[1] = NR_COMPOSENPP_1111(d[1], invca, g); - d[2] = NR_COMPOSENPP_1111(d[2], invca, b); - d[3] = NR_COMPOSEA_111(s[0], d[3]); - } - d += 4; - s += 1; - } - px += rs; - spx += srs; - } - } else { - for (y = h; y > 0; y--) { - unsigned char *d, *s; - d = (unsigned char *) px; - s = (unsigned char *) spx; - for (x = w; x > 0; x--) { - unsigned int ca; - ca = NR_PREMUL_112 (s[0], a); - if (ca == 0) { - /* Transparent FG, NOP */ - } else { - /* Full composition */ - unsigned int invca = 255*255-ca; // By swapping the arguments GCC can better optimize these calls - d[0] = NR_COMPOSENPP_1211(d[0], invca, r); - d[1] = NR_COMPOSENPP_1211(d[1], invca, g); - d[2] = NR_COMPOSENPP_1211(d[2], invca, b); - d[3] = NR_COMPOSEA_211(ca, d[3]); - } - d += 4; - s += 1; - } - px += rs; - spx += srs; - } - } -} - -/* RGB */ - -void -nr_R8G8B8_R8G8B8_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) -{ - unsigned int r, c; - -#ifdef WITH_MMX - if (NR_PIXOPS_MMX && alpha != 0) { - /* WARNING: MMX composer REQUIRES w > 0 and h > 0 */ - nr_mmx_R8G8B8_R8G8B8_R8G8B8A8_P (px, w, h, rs, spx, srs, alpha); - return; - } -#endif - - if (alpha == 0) { - /* NOP */ - } else if (alpha == 255) { - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - for (c = w; c > 0; c--) { - // dc' = (1 - alpha*sa) * dc + alpha*sc = (1 - sa) * dc + sc - if (s[3] == 0) { - /* NOP */ - } else if (s[3] == 255) { - d[0] = s[0]; - d[1] = s[1]; - d[2] = s[2]; - } else { - d[0] = NR_COMPOSEP11_1111(s[0], s[3], d[0]); - d[1] = NR_COMPOSEP11_1111(s[1], s[3], d[1]); - d[2] = NR_COMPOSEP11_1111(s[2], s[3], d[2]); - } - d += 3; - s += 4; - } - px += rs; - spx += srs; - } - } else { - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - for (c = w; c > 0; c--) { - unsigned int a; - a = NR_PREMUL_112(s[3], alpha); - // dc' = (1 - alpha*sa) * dc + alpha*sc - if (a == 0) { - /* NOP */ - } else { - d[0] = NR_COMPOSEP11_2211(NR_PREMUL_112(s[0], alpha), a, d[0]); - d[1] = NR_COMPOSEP11_2211(NR_PREMUL_112(s[1], alpha), a, d[1]); - d[2] = NR_COMPOSEP11_2211(NR_PREMUL_112(s[2], alpha), a, d[2]); - } - /* a == 255 is impossible, because alpha < 255 */ - d += 3; - s += 4; - } - px += rs; - spx += srs; - } - } -} - -void -nr_R8G8B8_R8G8B8_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) -{ - unsigned int r, c; - - if (alpha == 0) { - /* NOP */ - } else if (alpha == 255) { - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - for (c = w; c > 0; c--) { - // dc' = (1 - alpha*sa) * dc + alpha*sa*sc = (1 - sa) * dc + sa*sc - if (s[3] == 0) { - /* NOP */ - } else if (s[3] == 255) { - d[0] = s[0]; - d[1] = s[1]; - d[2] = s[2]; - } else { - d[0] = NR_COMPOSEN11_1111(s[0], s[3], d[0]); - d[1] = NR_COMPOSEN11_1111(s[1], s[3], d[1]); - d[2] = NR_COMPOSEN11_1111(s[2], s[3], d[2]); - } - d += 3; - s += 4; - } - px += rs; - spx += srs; - } - } else { - for (r = h; r > 0; r--) { - unsigned char *d = px; - const unsigned char *s = spx; - for (c = w; c > 0; c--) { - unsigned int a; - a = NR_PREMUL_112(s[3], alpha); - // dc' = (1 - alpha*sa) * dc + alpha*sa*sc - if (a == 0) { - /* NOP */ - } else { - d[0] = NR_COMPOSEN11_1211(s[0], a, d[0]); - d[1] = NR_COMPOSEN11_1211(s[1], a, d[1]); - d[2] = NR_COMPOSEN11_1211(s[2], a, d[2]); - } - /* a == 255 is impossible, because alpha < 255 */ - d += 3; - s += 4; - } - px += rs; - spx += srs; - } - } -} - -void -nr_R8G8B8_R8G8B8_R8G8B8A8_P_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) -{ - unsigned int x, y; - - for (y = h; y > 0; y--) { - unsigned char* d = px; - const unsigned char* s = spx; - const unsigned char* m = mpx; - for (x = w; x > 0; x--) { - unsigned int a; - a = NR_PREMUL_112(s[3], m[0]); - if (a == 0) { - /* NOP */ - } else if (a == 255*255) { - memcpy(d, s, 3); - } else { - // dc' = (1 - m*sa) * dc + m*sc - d[0] = NR_COMPOSEP11_2211(NR_PREMUL_112(s[0], m[0]), a, d[0]); - d[1] = NR_COMPOSEP11_2211(NR_PREMUL_112(s[1], m[0]), a, d[1]); - d[2] = NR_COMPOSEP11_2211(NR_PREMUL_112(s[2], m[0]), a, d[2]); - } - d += 3; - s += 4; - m += 1; - } - px += rs; - spx += srs; - mpx += mrs; - } -} - -void -nr_R8G8B8_R8G8B8_R8G8B8A8_N_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) -{ - unsigned int x, y; - - for (y = h; y > 0; y--) { - unsigned char* d = px; - const unsigned char* s = spx; - const unsigned char* m = mpx; - for (x = w; x > 0; x--) { - unsigned int a; - a = NR_PREMUL_112(s[3], m[0]); - if (a == 0) { - /* NOP */ - } else if (a == 255*255) { - memcpy(d, s, 3); - } else { - // dc' = (1 - m*sa) * dc + m*sa*sc - d[0] = NR_COMPOSEN11_1211(s[0], a, d[0]); - d[1] = NR_COMPOSEN11_1211(s[1], a, d[1]); - d[2] = NR_COMPOSEN11_1211(s[2], a, d[2]); - } - d += 3; - s += 4; - m += 1; - } - px += rs; - spx += srs; - mpx += mrs; - } -} - - diff --git a/src/libnr/nr-compose.h b/src/libnr/nr-compose.h deleted file mode 100644 index 4cecfac60..000000000 --- a/src/libnr/nr-compose.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef __NR_COMPOSE_H__ -#define __NR_COMPOSE_H__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * This code is in public domain - */ - -/* FINAL DST SRC */ - -void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); -void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); -void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); -void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); - -void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); -void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); -void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); -void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); - -/* FINAL DST SRC MASK */ - -void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8 (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int srs, - const unsigned char *mpx, int mrs); -void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8 (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int srs, - const unsigned char *mpx, int mrs); -void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8 (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int srs, - const unsigned char *mpx, int mrs); -void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8 (unsigned char *px, int w, int h, int rs, - const unsigned char *spx, int srs, - const unsigned char *mpx, int mrs); - -void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8 (unsigned char *p, int w, int h, int rs, - const unsigned char *s, int srs, - const unsigned char *m, int mrs); -void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8 (unsigned char *p, int w, int h, int rs, - const unsigned char *s, int srs, - const unsigned char *m, int mrs); -void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8 (unsigned char *p, int w, int h, int rs, - const unsigned char *s, int srs, - const unsigned char *m, int mrs); -void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8 (unsigned char *p, int w, int h, int rs, - const unsigned char *s, int srs, - const unsigned char *m, int mrs); - -/* FINAL DST MASK COLOR */ - -void nr_R8G8B8A8_N_EMPTY_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba); -void nr_R8G8B8A8_P_EMPTY_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba); - -void nr_R8G8B8_R8G8B8_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba); -void nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba); -void nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba); - -/* RGB */ - -void nr_R8G8B8_R8G8B8_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); -void nr_R8G8B8_R8G8B8_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); -void nr_R8G8B8_R8G8B8_R8G8B8A8_P_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs); -void nr_R8G8B8_R8G8B8_R8G8B8A8_N_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs); - -#endif diff --git a/src/libnr/nr-convert2geom.h b/src/libnr/nr-convert2geom.h index 2f87632fb..75098ce2b 100644 --- a/src/libnr/nr-convert2geom.h +++ b/src/libnr/nr-convert2geom.h @@ -9,7 +9,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <libnr/nr-matrix.h> #include <libnr/nr-rect.h> #include <libnr/nr-point.h> #include <2geom/affine.h> @@ -24,19 +23,6 @@ inline NR::Point from_2geom(Geom::Point const & _pt) { return NR::Point(_pt[0], _pt[1]); } -inline Geom::Affine to_2geom(NR::Matrix const & mat) { - Geom::Affine mat2geom(mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); - return mat2geom; -} -inline NR::Matrix from_2geom(Geom::Affine const & mat) { - NR::Matrix mat2geom(mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); - return mat2geom; -} - -inline Geom::Translate to_2geom(NR::translate const & mat) { - return Geom::Translate( mat.offset[0], mat.offset[1] ); -} - inline Geom::Rect to_2geom(NR::Rect const & rect) { Geom::Rect rect2geom(to_2geom(rect.min()), to_2geom(rect.max())); return rect2geom; @@ -54,13 +40,6 @@ inline Geom::OptRect to_2geom(boost::optional<NR::Rect> const & rect) { return rect2geom; } -inline NR::scale from_2geom(Geom::Scale const & in) { - return NR::scale(in[Geom::X], in[Geom::Y]); -} -inline Geom::Scale to_2geom(NR::scale const & in) { - return Geom::Scale(in[NR::X], in[NR::Y]); -} - #endif /* diff --git a/src/libnr/nr-convex-hull-ops.h b/src/libnr/nr-convex-hull-ops.h deleted file mode 100644 index 2e96bf367..000000000 --- a/src/libnr/nr-convex-hull-ops.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef SEEN_NR_CONVEX_HULL_FNS_H -#define SEEN_NR_CONVEX_HULL_FNS_H - -/* ex:set et ts=4 sw=4: */ - -/* - * A class representing the convex hull of a set of points. - * - * Copyright 2004 MenTaLguY <mental@rydia.net> - * - * This code is licensed under the GNU GPL; see COPYING for more information. - */ - -#include <libnr/nr-matrix-fns.h> -#include <libnr/nr-convex-hull.h> - -namespace NR { - -ConvexHull operator*(const Rect &r, const Matrix &m) { - ConvexHull points(r.corner(0)); - for ( unsigned i = 1 ; i < 4 ; i++ ) { - points.add(r.corner(i)); - } - return points; -} - -} /* namespace NR */ - -#endif diff --git a/src/libnr/nr-convex-hull.h b/src/libnr/nr-convex-hull.h deleted file mode 100644 index dafdd8840..000000000 --- a/src/libnr/nr-convex-hull.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef SEEN_NR_CONVEX_HULL_H -#define SEEN_NR_CONVEX_HULL_H - -/* ex:set et ts=4 sw=4: */ - -/* - * A class representing the convex hull of a set of points. - * - * Copyright 2004 MenTaLguY <mental@rydia.net> - * - * This code is licensed under the GNU GPL; see COPYING for more information. - */ - -#include <libnr/nr-rect.h> - -namespace NR { - -class ConvexHull { -public: - ConvexHull() : _bounds() {} - explicit ConvexHull(Point const &p) : _bounds(Rect(p, p)) {} - - boost::optional<Point> midpoint() const { - if (_bounds) { - return _bounds->midpoint(); - } else { - return boost::optional<Point>(); - } - } - - void add(Point const &p) { - if (_bounds) { - _bounds->expandTo(p); - } else { - _bounds = Rect(p, p); - } - } - void add(Rect const &r) { - // Note that this is a hack. when convexhull actually works - // you will need to add all four points. - _bounds = union_bounds(_bounds, r); - } - void add(ConvexHull const &h) { - if (h._bounds) { - add(*h._bounds); - } - } - - boost::optional<Rect> const &bounds() const { - return _bounds; - } - -private: - boost::optional<Rect> _bounds; -}; - -} /* namespace NR */ - -#endif diff --git a/src/libnr/nr-gradient.cpp b/src/libnr/nr-gradient.cpp deleted file mode 100644 index cb03c048b..000000000 --- a/src/libnr/nr-gradient.cpp +++ /dev/null @@ -1,554 +0,0 @@ -#define __NR_GRADIENT_C__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * MenTaLguY <mental@rydia.net> - *...Jasper van de Gronde <th.v.d.gronde@hccnet.nl> - * - * Copyright (C) 2009 Jasper van de Gronde - * Copyright (C) 2007 MenTaLguY - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001-2002 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -/* - * Derived in part from public domain code by Lauris Kaplinski - */ - -#include <cstring> -#include <libnr/nr-pixops.h> -#include <libnr/nr-pixblock-pixel.h> -#include <libnr/nr-blit.h> -#include <libnr/nr-gradient.h> -#include <libnr/nr-matrix-ops.h> -#include <glib/gtypes.h> -#include <stdio.h> - -/* Common */ - -#define NRG_MASK (NR_GRADIENT_VECTOR_LENGTH - 1) -#define NRG_2MASK ((long long) ((NR_GRADIENT_VECTOR_LENGTH << 1) - 1)) - -namespace { -inline unsigned char const *vector_index(int idx, - unsigned char const *vector) -{ - return vector + 4 * idx; -} - -template <NRGradientSpread spread> struct Spread; - -template <> -struct Spread<NR_GRADIENT_SPREAD_PAD> { -static double index_at(NR::Coord r, double const unity = 1.0) { - return r<0.0?0.0:r>unity?unity:r; -} -static unsigned char const *color_at(NR::Coord r, - unsigned char const *vector) -{ - return vector_index((int)(index_at(r, NR_GRADIENT_VECTOR_LENGTH - 1)+.5), vector); - //return vector_index((int)CLAMP(r, 0, (double)(NR_GRADIENT_VECTOR_LENGTH - 1)), vector); -} -}; - -template <> -struct Spread<NR_GRADIENT_SPREAD_REPEAT> { -static double index_at(NR::Coord r, double const unity = 1.0) { - return r<0.0?(unity+fmod(r,unity)):fmod(r,unity); -} -static unsigned char const *color_at(NR::Coord r, - unsigned char const *vector) -{ - return vector_index((int)(index_at(r, NR_GRADIENT_VECTOR_LENGTH - 1)+.5), vector); - //return vector_index((int)((long long)r & NRG_MASK), vector); -} -}; - -template <> -struct Spread<NR_GRADIENT_SPREAD_REFLECT> { -static double index_at(NR::Coord r, double const unity = 1.0) { - r = r<0.0?(2*unity+fmod(r,2*unity)):fmod(r,2*unity); - if (r>unity) r=2*unity-r; - return r; -} -static unsigned char const *color_at(NR::Coord r, - unsigned char const *vector) -{ - return vector_index((int)(index_at(r, NR_GRADIENT_VECTOR_LENGTH - 1)+.5), vector); - //int idx = (int) ((long long)r & NRG_2MASK); - //if (idx > NRG_MASK) idx = NRG_2MASK - idx; - //return vector_index(idx, vector); -} -}; - -template <NR_PIXBLOCK_MODE mode> struct ModeTraits; - -template <> -struct ModeTraits<NR_PIXBLOCK_MODE_R8G8B8A8N> { -static const unsigned bpp=4; -}; - -template <> -struct ModeTraits<NR_PIXBLOCK_MODE_R8G8B8A8P> { -static const unsigned bpp=4; -}; - -template <> -struct ModeTraits<NR_PIXBLOCK_MODE_R8G8B8> { -static const unsigned bpp=3; -}; - -template <> -struct ModeTraits<NR_PIXBLOCK_MODE_A8> { -static const unsigned bpp=1; -}; - -template <NR_PIXBLOCK_MODE mode, bool empty> -struct Compose { -static const unsigned bpp=ModeTraits<mode>::bpp; -static void compose(NRPixBlock *pb, unsigned char *dest, - NRPixBlock *spb, unsigned char const *src) -{ - nr_compose_pixblock_pixblock_pixel(pb, dest, spb, src); -} -}; - -template <> -struct Compose<NR_PIXBLOCK_MODE_R8G8B8A8N, true> { -static const unsigned bpp=4; -static void compose(NRPixBlock */*pb*/, unsigned char *dest, - NRPixBlock */*spb*/, unsigned char const *src) -{ - std::memcpy(dest, src, 4); -} -}; - -template <> -struct Compose<NR_PIXBLOCK_MODE_R8G8B8A8P, true> { -static const unsigned bpp=4; -static void compose(NRPixBlock */*pb*/, unsigned char *dest, - NRPixBlock */*spb*/, unsigned char const *src) -{ - dest[0] = NR_PREMUL_111(src[0], src[3]); - dest[1] = NR_PREMUL_111(src[1], src[3]); - dest[2] = NR_PREMUL_111(src[2], src[3]); - dest[3] = src[3]; -} -}; - -template <> -struct Compose<NR_PIXBLOCK_MODE_R8G8B8, true> { -static const unsigned bpp=3; -static void compose(NRPixBlock */*pb*/, unsigned char *dest, - NRPixBlock */*spb*/, unsigned char const *src) -{ - dest[0] = NR_COMPOSEN11_1111(src[0], src[3], 255); - dest[1] = NR_COMPOSEN11_1111(src[1], src[3], 255); - dest[2] = NR_COMPOSEN11_1111(src[2], src[3], 255); -} -}; - -template <> -struct Compose<NR_PIXBLOCK_MODE_A8, true> { -static const unsigned bpp=1; -static void compose(NRPixBlock */*pb*/, unsigned char *dest, - NRPixBlock */*spb*/, unsigned char const *src) -{ - dest[0] = src[3]; -} -}; - -template <> -struct Compose<NR_PIXBLOCK_MODE_R8G8B8A8N, false> { -static const unsigned bpp=4; -static void compose(NRPixBlock */*pb*/, unsigned char *dest, - NRPixBlock */*spb*/, unsigned char const *src) -{ - unsigned int ca; - ca = NR_COMPOSEA_112(src[3], dest[3]); - dest[0] = NR_COMPOSENNN_111121(src[0], src[3], dest[0], dest[3], ca); - dest[1] = NR_COMPOSENNN_111121(src[1], src[3], dest[1], dest[3], ca); - dest[2] = NR_COMPOSENNN_111121(src[2], src[3], dest[2], dest[3], ca); - dest[3] = NR_NORMALIZE_21(ca); -} -}; - -template <> -struct Compose<NR_PIXBLOCK_MODE_R8G8B8A8P, false> { -static const unsigned bpp=4; -static void compose(NRPixBlock */*pb*/, unsigned char *dest, - NRPixBlock */*spb*/, unsigned char const *src) -{ - dest[0] = NR_COMPOSENPP_1111(src[0], src[3], dest[0]); - dest[1] = NR_COMPOSENPP_1111(src[1], src[3], dest[1]); - dest[2] = NR_COMPOSENPP_1111(src[2], src[3], dest[2]); - dest[3] = NR_COMPOSEA_111(src[3], dest[3]); -} -}; - -template <> -struct Compose<NR_PIXBLOCK_MODE_R8G8B8, false> { -static const unsigned bpp=3; -static void compose(NRPixBlock */*pb*/, unsigned char *dest, - NRPixBlock */*spb*/, unsigned char const *src) -{ - dest[0] = NR_COMPOSEN11_1111(src[0], src[3], dest[0]); - dest[1] = NR_COMPOSEN11_1111(src[1], src[3], dest[1]); - dest[2] = NR_COMPOSEN11_1111(src[2], src[3], dest[2]); -} -}; - -template <typename Subtype, typename spread> -static void -render_spread(NRGradientRenderer *gr, NRPixBlock *pb) -{ - switch (pb->mode) { - case NR_PIXBLOCK_MODE_R8G8B8A8N: - if (pb->empty) { - typedef Compose<NR_PIXBLOCK_MODE_R8G8B8A8N, true> compose; - Subtype::template render<compose, spread>(gr, pb); - } else { - typedef Compose<NR_PIXBLOCK_MODE_R8G8B8A8N, false> compose; - Subtype::template render<compose, spread>(gr, pb); - } - break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: - if (pb->empty) { - typedef Compose<NR_PIXBLOCK_MODE_R8G8B8A8P, true> compose; - Subtype::template render<compose, spread>(gr, pb); - } else { - typedef Compose<NR_PIXBLOCK_MODE_R8G8B8A8P, false> compose; - Subtype::template render<compose, spread>(gr, pb); - } - break; - case NR_PIXBLOCK_MODE_R8G8B8: - if (pb->empty) { - typedef Compose<NR_PIXBLOCK_MODE_R8G8B8, true> compose; - Subtype::template render<compose, spread>(gr, pb); - } else { - typedef Compose<NR_PIXBLOCK_MODE_R8G8B8, false> compose; - Subtype::template render<compose, spread>(gr, pb); - } - break; - case NR_PIXBLOCK_MODE_A8: - if (pb->empty) { - typedef Compose<NR_PIXBLOCK_MODE_A8, true> compose; - Subtype::template render<compose, spread>(gr, pb); - } else { - typedef Compose<NR_PIXBLOCK_MODE_A8, false> compose; - Subtype::template render<compose, spread>(gr, pb); - } - break; - } -} - -template <typename Subtype> -static void -render(NRRenderer *r, NRPixBlock *pb, NRPixBlock */*m*/) -{ - NRGradientRenderer *gr = static_cast<NRGradientRenderer *>(r); - - switch (gr->spread) { - case NR_GRADIENT_SPREAD_REPEAT: - render_spread<Subtype, Spread<NR_GRADIENT_SPREAD_REPEAT> >(gr, pb); - break; - case NR_GRADIENT_SPREAD_REFLECT: - render_spread<Subtype, Spread<NR_GRADIENT_SPREAD_REFLECT> >(gr, pb); - break; - case NR_GRADIENT_SPREAD_PAD: - default: - render_spread<Subtype, Spread<NR_GRADIENT_SPREAD_PAD> >(gr, pb); - } -} -} - -/* Linear */ - -namespace { - -struct Linear { -template <typename compose, typename spread> -static void render(NRGradientRenderer *gr, NRPixBlock *pb) { - NRLGradientRenderer *lgr = static_cast<NRLGradientRenderer *>(gr); - - int x, y; - unsigned char *d; - double pos; - NRPixBlock spb; - int x0, y0, width, height, rs; - - x0 = pb->area.x0; - y0 = pb->area.y0; - width = pb->area.x1 - pb->area.x0; - height = pb->area.y1 - pb->area.y0; - rs = pb->rs; - - nr_pixblock_setup_extern(&spb, NR_PIXBLOCK_MODE_R8G8B8A8N, - 0, 0, NR_GRADIENT_VECTOR_LENGTH, 1, - (unsigned char *) lgr->vector, - 4 * NR_GRADIENT_VECTOR_LENGTH, 0, 0); - - for (y = 0; y < height; y++) { - d = NR_PIXBLOCK_PX(pb) + y * rs; - pos = (y + y0 - lgr->y0) * lgr->dy + (0 + x0 - lgr->x0) * lgr->dx; - for (x = 0; x < width; x++) { - unsigned char const *s=spread::color_at(pos, lgr->vector); - compose::compose(pb, d, &spb, s); - d += compose::bpp; - pos += lgr->dx; - } - } - - nr_pixblock_release(&spb); -} -}; - -} - -NRRenderer * -nr_lgradient_renderer_setup (NRLGradientRenderer *lgr, - const unsigned char *cv, - unsigned int spread, - const NR::Matrix *gs2px, - float x0, float y0, - float x1, float y1) -{ - NR::Matrix n2gs, n2px, px2n; - - lgr->render = &render<Linear>; - - lgr->vector = cv; - lgr->spread = spread; - - n2gs[0] = x1 - x0; - n2gs[1] = y1 - y0; - n2gs[2] = y1 - y0; - n2gs[3] = x0 - x1; - n2gs[4] = x0; - n2gs[5] = y0; - - n2px = n2gs * (*gs2px); - px2n = n2px.inverse(); - - lgr->x0 = n2px[4] - 0.5; // These -0.5 offsets make sure that the gradient is sampled in the MIDDLE of each pixel. - lgr->y0 = n2px[5] - 0.5; - lgr->dx = px2n[0] * (NR_GRADIENT_VECTOR_LENGTH-1); - lgr->dy = px2n[2] * (NR_GRADIENT_VECTOR_LENGTH-1); - - return (NRRenderer *) lgr; -} - -/* Radial */ - -/* - * The archetype is following - * - * gx gy - pixel coordinates - * Px Py - coordinates, where Fx Fy - gx gy line intersects with circle - * - * (1) (gx - fx) * (Py - fy) = (gy - fy) * (Px - fx) - * (2) (Px - cx) * (Px - cx) + (Py - cy) * (Py - cy) = r * r - * - * (3) Py = (Px - fx) * (gy - fy) / (gx - fx) + fy - * (4) (gy - fy) / (gx - fx) = D - * (5) Py = D * Px - D * fx + fy - * - * (6) D * fx - fy + cy = N - * (7) Px * Px - 2 * Px * cx + cx * cx + (D * Px) * (D * Px) - 2 * (D * Px) * N + N * N = r * r - * (8) (D * D + 1) * (Px * Px) - 2 * (cx + D * N) * Px + cx * cx + N * N = r * r - * - * (9) A = D * D + 1 - * (10) B = -2 * (cx + D * N) - * (11) C = cx * cx + N * N - r * r - * - * (12) Px = (-B +- SQRT(B * B - 4 * A * C)) / 2 * A - */ - -namespace { - -struct SymmetricRadial { -template <typename compose, typename spread> -static void render(NRGradientRenderer *gr, NRPixBlock *pb) -{ - NRRGradientRenderer *rgr = static_cast<NRRGradientRenderer *>(gr); - - NR::Coord const dx = rgr->px2gs[0]; - NR::Coord const dy = rgr->px2gs[1]; - - NRPixBlock spb; - nr_pixblock_setup_extern(&spb, NR_PIXBLOCK_MODE_R8G8B8A8N, - 0, 0, NR_GRADIENT_VECTOR_LENGTH, 1, - (unsigned char *) rgr->vector, - 4 * NR_GRADIENT_VECTOR_LENGTH, - 0, 0); - - for (int y = pb->area.y0; y < pb->area.y1; y++) { - unsigned char *d = NR_PIXBLOCK_PX(pb) + (y - pb->area.y0) * pb->rs; - NR::Coord gx = rgr->px2gs[0] * pb->area.x0 + rgr->px2gs[2] * y + rgr->px2gs[4]; - NR::Coord gy = rgr->px2gs[1] * pb->area.x0 + rgr->px2gs[3] * y + rgr->px2gs[5]; - for (int x = pb->area.x0; x < pb->area.x1; x++) { - NR::Coord const pos = sqrt(((gx*gx) + (gy*gy))); - unsigned char const *s=spread::color_at(pos, rgr->vector); - compose::compose(pb, d, &spb, s); - d += compose::bpp; - gx += dx; - gy += dy; - } - } - - nr_pixblock_release(&spb); -} -}; - -struct Radial { -template <typename compose, typename spread> -static void render(NRGradientRenderer *gr, NRPixBlock *pb) -{ - NRRGradientRenderer *rgr = static_cast<NRRGradientRenderer *>(gr); - int const x0 = pb->area.x0; - int const y0 = pb->area.y0; - int const x1 = pb->area.x1; - int const y1 = pb->area.y1; - int const rs = pb->rs; - - NRPixBlock spb; - nr_pixblock_setup_extern(&spb, NR_PIXBLOCK_MODE_R8G8B8A8N, - 0, 0, NR_GRADIENT_VECTOR_LENGTH, 1, - (unsigned char *) rgr->vector, - 4 * NR_GRADIENT_VECTOR_LENGTH, - 0, 0); - - for (int y = y0; y < y1; y++) { - unsigned char *d = NR_PIXBLOCK_PX(pb) + (y - y0) * rs; - NR::Coord gx = rgr->px2gs[0] * x0 + rgr->px2gs[2] * y + rgr->px2gs[4]; - NR::Coord gy = rgr->px2gs[1] * x0 + rgr->px2gs[3] * y + rgr->px2gs[5]; - NR::Coord const dx = rgr->px2gs[0]; - NR::Coord const dy = rgr->px2gs[1]; - for (int x = x0; x < x1; x++) { - NR::Coord const gx2 = gx * gx; - NR::Coord const gxy2 = gx2 + gy * gy; - NR::Coord const qgx2_4 = gx2 - rgr->C * gxy2; - /* INVARIANT: qgx2_4 >= 0.0 */ - /* qgx2_4 = MAX(qgx2_4, 0.0); */ - NR::Coord const pxgx = gx + sqrt(qgx2_4); - /* We can safely divide by 0 here */ - /* If we are sure pxgx cannot be -0 */ - NR::Coord const pos = gxy2 / pxgx * (NR_GRADIENT_VECTOR_LENGTH-1); - - unsigned char const *s; - if (pos < (1U << 31)) { - s = spread::color_at(pos, rgr->vector); - } else { - s = vector_index(NR_GRADIENT_VECTOR_LENGTH - 1, rgr->vector); - } - - compose::compose(pb, d, &spb, s); - d += compose::bpp; - - gx += dx; - gy += dy; - } - } - - nr_pixblock_release(&spb); -} -}; - -} - -static void nr_rgradient_render_block_end(NRRenderer *r, NRPixBlock *pb, NRPixBlock *m); - -NRRenderer * -nr_rgradient_renderer_setup(NRRGradientRenderer *rgr, - unsigned char const *cv, - unsigned spread, - NR::Matrix const *gs2px, - float cx, float cy, - float fx, float fy, - float r) -{ - rgr->vector = cv; - rgr->spread = spread; - - if (r < NR_EPSILON) { - rgr->render = nr_rgradient_render_block_end; - } else if (NR_DF_TEST_CLOSE(cx, fx, NR_EPSILON) && - NR_DF_TEST_CLOSE(cy, fy, NR_EPSILON)) { - rgr->render = render<SymmetricRadial>; - - rgr->px2gs = gs2px->inverse(); - rgr->px2gs[0] *= (NR_GRADIENT_VECTOR_LENGTH-1) / r; - rgr->px2gs[1] *= (NR_GRADIENT_VECTOR_LENGTH-1) / r; - rgr->px2gs[2] *= (NR_GRADIENT_VECTOR_LENGTH-1) / r; - rgr->px2gs[3] *= (NR_GRADIENT_VECTOR_LENGTH-1) / r; - rgr->px2gs[4] -= cx; - rgr->px2gs[5] -= cy; - rgr->px2gs[4] *= (NR_GRADIENT_VECTOR_LENGTH-1) / r; - rgr->px2gs[5] *= (NR_GRADIENT_VECTOR_LENGTH-1) / r; - rgr->px2gs[4] += 0.5*(rgr->px2gs[0]+rgr->px2gs[2]); // These offsets make sure the gradient is sampled in the MIDDLE of each pixel - rgr->px2gs[5] += 0.5*(rgr->px2gs[1]+rgr->px2gs[3]); - - rgr->cx = 0.0; - rgr->cy = 0.0; - rgr->fx = rgr->cx; - rgr->fy = rgr->cy; - rgr->r = 1.0; - } else { - rgr->render = render<Radial>; - - NR::Coord const df = hypot(fx - cx, fy - cy); - if (df >= r) { - fx = cx + (fx - cx ) * r / (float) df; - fy = cy + (fy - cy ) * r / (float) df; - } - - NR::Matrix n2gs; - n2gs[0] = cx - fx; - n2gs[1] = cy - fy; - n2gs[2] = cy - fy; - n2gs[3] = fx - cx; - n2gs[4] = fx; - n2gs[5] = fy; - - NR::Matrix n2px; - n2px = n2gs * (*gs2px); - rgr->px2gs = n2px.inverse(); - rgr->px2gs[4] += 0.5*(rgr->px2gs[0]+rgr->px2gs[2]); // These offsets make sure the gradient is sampled in the MIDDLE of each pixel - rgr->px2gs[5] += 0.5*(rgr->px2gs[1]+rgr->px2gs[3]); - - rgr->cx = 1.0; - rgr->cy = 0.0; - rgr->fx = 0.0; - rgr->fy = 0.0; - rgr->r = r / (float) hypot(fx - cx, fy - cy); - rgr->C = 1.0F - rgr->r * rgr->r; - /* INVARIANT: C < 0 */ - rgr->C = MIN(rgr->C, -NR_EPSILON); - } - - return (NRRenderer *) rgr; -} - -static void -nr_rgradient_render_block_end(NRRenderer *r, NRPixBlock *pb, NRPixBlock *m) -{ - unsigned char const *c = ((NRRGradientRenderer *) r)->vector + 4 * (NR_GRADIENT_VECTOR_LENGTH - 1); - - nr_blit_pixblock_mask_rgba32(pb, m, (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]); -} - -/* - 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 : diff --git a/src/libnr/nr-gradient.h b/src/libnr/nr-gradient.h deleted file mode 100644 index f5afdc98d..000000000 --- a/src/libnr/nr-gradient.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef __NR_GRADIENT_H__ -#define __NR_GRADIENT_H__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001-2002 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -/* - * Derived in part from public domain code by Lauris Kaplinski - */ - -#include <libnr/nr-matrix.h> -#include <libnr/nr-render.h> - -#define NR_GRADIENT_VECTOR_BITS 10 -#define NR_GRADIENT_VECTOR_LENGTH (1<<NR_GRADIENT_VECTOR_BITS) - -enum NRGradientSpread { - NR_GRADIENT_SPREAD_PAD, - NR_GRADIENT_SPREAD_REFLECT, - NR_GRADIENT_SPREAD_REPEAT -}; - -struct NRGradientRenderer : public NRRenderer { - const unsigned char *vector; - unsigned int spread; -}; - -/* Linear */ - -struct NRLGradientRenderer : public NRGradientRenderer { - double x0, y0; - double dx, dy; -}; - -NRRenderer *nr_lgradient_renderer_setup (NRLGradientRenderer *lgr, - const unsigned char *cv, - unsigned int spread, - const NR::Matrix *gs2px, - float x0, float y0, - float x1, float y1); - -/* Radial */ - -struct NRRGradientRenderer : public NRGradientRenderer { - NR::Matrix px2gs; - float cx, cy; - float fx, fy; - float r; - float C; -}; - -NRRenderer *nr_rgradient_renderer_setup (NRRGradientRenderer *rgr, - const unsigned char *cv, - unsigned int spread, - const NR::Matrix *gs2px, - float cx, float cy, - float fx, float fy, - float r); - - - -#endif -/* - * 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 : diff --git a/src/libnr/nr-matrix-div.cpp b/src/libnr/nr-matrix-div.cpp deleted file mode 100644 index d6fb598b8..000000000 --- a/src/libnr/nr-matrix-div.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "libnr/nr-matrix-ops.h" -#include "libnr/nr-point-matrix-ops.h" - -NR::Point operator/(NR::Point const &p, NR::Matrix const &m) { - return p * m.inverse(); -} - -NR::Matrix operator/(NR::Matrix const &a, NR::Matrix const &b) { - return a * b.inverse(); -} - - -/* - 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 : diff --git a/src/libnr/nr-matrix-div.h b/src/libnr/nr-matrix-div.h deleted file mode 100644 index 8669e2ce2..000000000 --- a/src/libnr/nr-matrix-div.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef SEEN_LIBNR_NR_MATRIX_DIV_H -#define SEEN_LIBNR_NR_MATRIX_DIV_H - -#include "libnr/nr-forward.h" - -NR::Point operator/(NR::Point const &, NR::Matrix const &); - -NR::Matrix operator/(NR::Matrix const &, NR::Matrix const &); - -#endif /* !SEEN_LIBNR_NR_MATRIX_DIV_H */ - -/* - 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 : diff --git a/src/libnr/nr-matrix-fns.cpp b/src/libnr/nr-matrix-fns.cpp deleted file mode 100644 index c8eb986fa..000000000 --- a/src/libnr/nr-matrix-fns.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include <libnr/nr-matrix-fns.h> -#include <cstdio> - -namespace NR { - -Matrix elliptic_quadratic_form(Matrix const &m) { - double const od = m[0] * m[1] + m[2] * m[3]; - return Matrix((m[0]*m[0] + m[1]*m[1]), od, - od, (m[2]*m[2] + m[3]*m[3]), - 0, 0); -/* def quadratic_form((a, b), (c, d)): - return ((a*a + c*c), a*c+b*d),(a*c+b*d, (b*b + d*d)) */ -} - -Eigen::Eigen(Matrix const &m) { - double const B = -m[0] - m[3]; - double const C = m[0]*m[3] - m[1]*m[2]; - double const center = -B/2.0; - double const delta = sqrt(B*B-4*C)/2.0; - values = Point(center + delta, center - delta); - for (int i = 0; i < 2; i++) { - vectors[i] = unit_vector(rot90(Point(m[0]-values[i], m[1]))); - } -} - -/** Returns just the scale/rotate/skew part of the matrix without the translation part. */ -Matrix transform(Matrix const &m) { - Matrix const ret(m[0], m[1], - m[2], m[3], - 0, 0); - return ret; -} - -translate get_translation(Matrix const &m) { - return translate(m[4], m[5]); -} - -void matrix_print(const gchar *say, Matrix const &m) -{ - printf ("%s %g %g %g %g %g %g\n", say, m[0], m[1], m[2], m[3], m[4], m[5]); -} - -} // namespace NR - - -/* - 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 : diff --git a/src/libnr/nr-matrix-fns.h b/src/libnr/nr-matrix-fns.h deleted file mode 100644 index a46aca909..000000000 --- a/src/libnr/nr-matrix-fns.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef SEEN_NR_MATRIX_FNS_H -#define SEEN_NR_MATRIX_FNS_H - -#include "nr-matrix.h" -#include <math.h> - -namespace NR { - -/** Given a matrix m such that unit_circle = m*x, this returns the - * quadratic form x*A*x = 1. */ -Matrix elliptic_quadratic_form(Matrix const &m); - -/** Given a matrix (ignoring the translation) this returns the eigen - * values and vectors. */ -class Eigen{ -public: - Point vectors[2]; - Point values; - Eigen(Matrix const &m); -}; - -// Matrix factories -Matrix from_basis(const Point x_basis, const Point y_basis, const Point offset=Point(0,0)); - -Matrix identity(); - -double expansion(Matrix const &m); -inline double expansionX(Matrix const &m) { return hypot(m[0], m[1]); } -inline double expansionY(Matrix const &m) { return hypot(m[2], m[3]); } - -bool transform_equalp(Matrix const &m0, Matrix const &m1, NR::Coord const epsilon); -bool translate_equalp(Matrix const &m0, Matrix const &m1, NR::Coord const epsilon); -bool matrix_equalp(Matrix const &m0, Matrix const &m1, NR::Coord const epsilon); - -Matrix transform(Matrix const &m); -translate get_translation(Matrix const &m); - -void matrix_print(const gchar *say, Matrix const &m); - -} // namespace NR - -#endif /* !SEEN_NR_MATRIX_FNS_H */ - -/* - 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 : diff --git a/src/libnr/nr-matrix-ops.h b/src/libnr/nr-matrix-ops.h deleted file mode 100644 index 2c9c93124..000000000 --- a/src/libnr/nr-matrix-ops.h +++ /dev/null @@ -1,41 +0,0 @@ -/* operator functions for NR::Matrix. */ -#ifndef SEEN_NR_MATRIX_OPS_H -#define SEEN_NR_MATRIX_OPS_H - -#include <libnr/nr-matrix.h> - -namespace NR { - -inline bool operator==(Matrix const &a, Matrix const &b) -{ - for(unsigned i = 0; i < 6; ++i) { - if ( a[i] != b[i] ) { - return false; - } - } - return true; -} - -inline bool operator!=(Matrix const &a, Matrix const &b) -{ - return !( a == b ); -} - -Matrix operator*(Matrix const &a, Matrix const &b); - -inline Matrix &operator*=(Matrix &a, Matrix const &b) { a = a * b; return a; } - -} /* namespace NR */ - -#endif /* !SEEN_NR_MATRIX_OPS_H */ - -/* - 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 : diff --git a/src/libnr/nr-matrix-rotate-ops.cpp b/src/libnr/nr-matrix-rotate-ops.cpp deleted file mode 100644 index d16809318..000000000 --- a/src/libnr/nr-matrix-rotate-ops.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "libnr/nr-matrix-ops.h" - -NR::Matrix operator*(NR::Matrix const &m, NR::rotate const &r) -{ - return m * NR::Matrix(r); -} - - -/* - 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 : diff --git a/src/libnr/nr-matrix-rotate-ops.h b/src/libnr/nr-matrix-rotate-ops.h deleted file mode 100644 index a3cc4c806..000000000 --- a/src/libnr/nr-matrix-rotate-ops.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef SEEN_LIBNR_NR_MATRIX_ROTATE_OPS_H -#define SEEN_LIBNR_NR_MATRIX_ROTATE_OPS_H - -#include "libnr/nr-forward.h" - -NR::Matrix operator*(NR::Matrix const &m, NR::rotate const &r); - - -#endif /* !SEEN_LIBNR_NR_MATRIX_ROTATE_OPS_H */ - -/* - 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 : diff --git a/src/libnr/nr-matrix-scale-ops.h b/src/libnr/nr-matrix-scale-ops.h deleted file mode 100644 index d030bb66c..000000000 --- a/src/libnr/nr-matrix-scale-ops.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef SEEN_LIBNR_NR_MATRIX_SCALE_OPS_H -#define SEEN_LIBNR_NR_MATRIX_SCALE_OPS_H -/** \file - * Declarations (and definition if inline) of operator blah (NR::Matrix, NR::scale). - */ - -#include "libnr/nr-forward.h" - -namespace NR { - -inline Matrix &operator/=(Matrix &m, scale const &s) { - m[0] /= s[X]; m[1] /= s[Y]; - m[2] /= s[X]; m[3] /= s[Y]; - m[4] /= s[X]; m[5] /= s[Y]; - return m; -} - -inline Matrix &operator*=(Matrix &m, scale const &s) { - m[0] *= s[X]; m[1] *= s[Y]; - m[2] *= s[X]; m[3] *= s[Y]; - m[4] *= s[X]; m[5] *= s[Y]; - return m; -} - -inline Matrix operator/(Matrix const &m, scale const &s) { Matrix ret(m); ret /= s; return ret; } - -inline Matrix operator*(Matrix const &m, scale const &s) { Matrix ret(m); ret *= s; return ret; } - -} - -#endif /* !SEEN_LIBNR_NR_MATRIX_SCALE_OPS_H */ diff --git a/src/libnr/nr-matrix-test.h b/src/libnr/nr-matrix-test.h deleted file mode 100644 index 6477523fc..000000000 --- a/src/libnr/nr-matrix-test.h +++ /dev/null @@ -1,191 +0,0 @@ -#include <cxxtest/TestSuite.h> - -#include <libnr/nr-matrix.h> -#include <libnr/nr-matrix-fns.h> -#include <libnr/nr-matrix-ops.h> -#include <libnr/nr-matrix-rotate-ops.h> -#include <libnr/nr-matrix-scale-ops.h> -#include <libnr/nr-point-matrix-ops.h> -#include <libnr/nr-rotate.h> -#include <libnr/nr-rotate-ops.h> -#include <libnr/nr-scale-ops.h> -#include <libnr/nr-scale-translate-ops.h> -#include <libnr/nr-translate.h> -#include <libnr/nr-translate-ops.h> -#include <libnr/nr-translate-scale-ops.h> - -inline bool point_equalp(NR::Point const &a, NR::Point const &b) -{ - return ( NR_DF_TEST_CLOSE(a[NR::X], b[NR::X], 1e-5) && - NR_DF_TEST_CLOSE(a[NR::Y], b[NR::Y], 1e-5) ); -} - -class NrMatrixTest : public CxxTest::TestSuite -{ -public: - - NrMatrixTest() : - m_id( NR::identity() ), - r_id( NR::Point(1, 0) ), - t_id( 0, 0 ), - c16( 1.0, 2.0, - 3.0, 4.0, - 5.0, 6.0), - r86( NR::Point(.8, .6) ), - mr86( r86 ), - t23( 2.0, 3.0 ), - s_id( 1.0, 1.0 ) - { - } - virtual ~NrMatrixTest() {} - -// createSuite and destroySuite get us per-suite setup and teardown -// without us having to worry about static initialization order, etc. - static NrMatrixTest *createSuite() { return new NrMatrixTest(); } - static void destroySuite( NrMatrixTest *suite ) { delete suite; } - - NR::Matrix const m_id; - NR::rotate const r_id; - NR::translate const t_id; - NR::Matrix const c16; - NR::rotate const r86; - NR::Matrix const mr86; - NR::translate const t23; - NR::scale const s_id; - - - - - void testCtorsAssignmentOp(void) - { - NR::Matrix const c16_copy(c16); - NR::Matrix c16_eq(m_id); - c16_eq = c16; - for(unsigned i = 0; i < 6; ++i) { - TS_ASSERT_EQUALS( c16[i], 1.0 + i ); - TS_ASSERT_EQUALS( c16[i], c16_copy[i] ); - TS_ASSERT_EQUALS( c16[i], c16_eq[i] ); - TS_ASSERT_EQUALS( m_id[i], double( i == 0 || i == 3 ) ); - } - } - - void testScaleCtor(void) - { - NR::scale const s(2.0, 3.0); - NR::Matrix const ms(s); - NR::Point const p(5.0, 7.0); - TS_ASSERT_EQUALS( p * s, NR::Point(10.0, 21.0) ); - TS_ASSERT_EQUALS( p * ms, NR::Point(10.0, 21.0) ); - } - - void testRotateCtor(void) - { - NR::Point const p0(1.0, 0.0); - NR::Point const p90(0.0, 1.0); - TS_ASSERT_EQUALS( p0 * r86, NR::Point(.8, .6) ); - TS_ASSERT_EQUALS( p0 * mr86, NR::Point(.8, .6) ); - TS_ASSERT_EQUALS( p90 * r86, NR::Point(-.6, .8) ); - TS_ASSERT_EQUALS( p90 * mr86, NR::Point(-.6, .8) ); - TS_ASSERT( matrix_equalp(NR::Matrix( r86 * r86 ), - mr86 * mr86, - 1e-14) ); - } - - void testTranslateCtor(void) - { - NR::Matrix const mt23(t23); - NR::Point const b(-2.0, 3.0); - TS_ASSERT_EQUALS( b * t23, b * mt23 ); - } - - void testIdentity(void) - { - TS_ASSERT( m_id.test_identity() ); - TS_ASSERT( NR::Matrix(t_id).test_identity() ); - TS_ASSERT( !(NR::Matrix(NR::translate(-2, 3)).test_identity()) ); - TS_ASSERT( NR::Matrix(r_id).test_identity() ); - NR::rotate const rot180(NR::Point(-1, 0)); - TS_ASSERT( !(NR::Matrix(rot180).test_identity()) ); - TS_ASSERT( NR::Matrix(s_id).test_identity() ); - TS_ASSERT( !(NR::Matrix(NR::scale(1.0, 0.0)).test_identity()) ); - TS_ASSERT( !(NR::Matrix(NR::scale(0.0, 1.0)).test_identity()) ); - TS_ASSERT( !(NR::Matrix(NR::scale(1.0, -1.0)).test_identity()) ); - TS_ASSERT( !(NR::Matrix(NR::scale(-1.0, -1.0)).test_identity()) ); - } - - void testInverse(void) - { - TS_ASSERT_EQUALS( m_id.inverse(), m_id ); - TS_ASSERT_EQUALS( NR::Matrix(t23).inverse(), NR::Matrix(NR::translate(-2.0, -3.0)) ); - NR::scale const s2(-4.0, 2.0); - NR::scale const sp5(-.25, .5); - TS_ASSERT_EQUALS( NR::Matrix(s2).inverse(), NR::Matrix(sp5) ); - TS_ASSERT_EQUALS( NR::Matrix(sp5).inverse(), NR::Matrix(s2) ); - } - - void testEllipticQuadraticForm(void) - { - NR::Matrix const aff(1.0, 1.0, - 0.0, 1.0, - 5.0, 6.0); - NR::Matrix const invaff = aff.inverse(); - TS_ASSERT_EQUALS( invaff[1], -1.0 ); - - NR::Matrix const ef(elliptic_quadratic_form(invaff)); - NR::Matrix const exp_ef(2, -1, - -1, 1, - 0, 0); - TS_ASSERT_EQUALS( ef, exp_ef ); - } - - void testMatrixStarRotate(void) - { - NR::Matrix const ma(2.0, -1.0, - 4.0, 4.0, - -0.5, 2.0); - NR::Matrix const a_r86( ma * r86 ); - NR::Matrix const ma1( a_r86 * r86.inverse() ); - TS_ASSERT( matrix_equalp(ma1, ma, 1e-12) ); - NR::Matrix const exp_a_r86( 2*.8 + -1*-.6, 2*.6 + -1*.8, - 4*.8 + 4*-.6, 4*.6 + 4*.8, - -.5*.8 + 2*-.6, -.5*.6 + 2*.8 ); - TS_ASSERT( matrix_equalp(a_r86, exp_a_r86, 1e-12) ); - } - - void testTranslateStarScale_ScaleStarTranslate(void) - { - NR::translate const t2n4(2, -4); - NR::scale const sn2_8(-2, 8); - NR::Matrix const exp_ts(-2, 0, - 0, 8, - -4, -32); - NR::Matrix const exp_st(-2, 0, - 0, 8, - 2, -4); - TS_ASSERT_EQUALS( exp_ts, t2n4 * sn2_8 ); - TS_ASSERT_EQUALS( exp_st, sn2_8 * t2n4 ); - } - - void testMatrixStarScale(void) - { - NR::Matrix const ma(2.0, -1.0, - 4.0, 4.0, - -0.5, 2.0); - NR::scale const sn2_8(-2, 8); - NR::Matrix const exp_as(-4, -8, - -8, 32, - 1, 16); - TS_ASSERT_EQUALS( ma * sn2_8, exp_as ); - } -}; - -/* - 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 : diff --git a/src/libnr/nr-matrix-translate-ops.h b/src/libnr/nr-matrix-translate-ops.h deleted file mode 100644 index 3d944651f..000000000 --- a/src/libnr/nr-matrix-translate-ops.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef SEEN_LIBNR_NR_MATRIX_TRANSLATE_OPS_H -#define SEEN_LIBNR_NR_MATRIX_TRANSLATE_OPS_H - -/** \file - * Declarations (and definition if inline) of operator - * blah (NR::Matrix, NR::translate). - */ - -#include "libnr/nr-matrix.h" -#include "libnr/nr-translate.h" - -namespace NR { - -inline Matrix &operator*=(Matrix &m, translate const &t) { - m[4] += t[X]; - m[5] += t[Y]; - return m; -} - -inline Matrix operator*(Matrix const &m, translate const &t) { Matrix ret(m); ret *= t; return ret; } - -inline Matrix operator/(Matrix const &numer, translate const &denom) { return numer * translate(-denom.offset); } - -} - -#endif /* !SEEN_LIBNR_NR_MATRIX_TRANSLATE_OPS_H */ - -/* - 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 : diff --git a/src/libnr/nr-matrix.cpp b/src/libnr/nr-matrix.cpp deleted file mode 100644 index 4f94dd3df..000000000 --- a/src/libnr/nr-matrix.cpp +++ /dev/null @@ -1,291 +0,0 @@ -#define __NR_MATRIX_C__ - -/** \file - * Various matrix routines. Currently includes some NR::rotate etc. routines too. - */ - -/* - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * This code is in public domain - */ - -#include <cstdlib> -#include "nr-matrix.h" -#include "nr-matrix-fns.h" - - - -/** - * Implement NR functions and methods - */ -namespace NR { - - - - - -/** - * Multiply two matrices together - */ -Matrix operator*(Matrix const &m0, Matrix const &m1) -{ - NR::Coord const d0 = m0[0] * m1[0] + m0[1] * m1[2]; - NR::Coord const d1 = m0[0] * m1[1] + m0[1] * m1[3]; - NR::Coord const d2 = m0[2] * m1[0] + m0[3] * m1[2]; - NR::Coord const d3 = m0[2] * m1[1] + m0[3] * m1[3]; - NR::Coord const d4 = m0[4] * m1[0] + m0[5] * m1[2] + m1[4]; - NR::Coord const d5 = m0[4] * m1[1] + m0[5] * m1[3] + m1[5]; - - Matrix ret( d0, d1, d2, d3, d4, d5 ); - - return ret; -} - - - - - -/** - * Return the inverse of this matrix. If an inverse is not defined, - * then return the identity matrix. - */ -Matrix Matrix::inverse() const -{ - Matrix d(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); - - NR::Coord const det = _c[0] * _c[3] - _c[1] * _c[2]; - if (!NR_DF_TEST_CLOSE(det, 0.0, NR_EPSILON)) { - - NR::Coord const idet = 1.0 / det; - NR::Coord *dest = d._c; - - /*0*/ *dest++ = _c[3] * idet; - /*1*/ *dest++ = -_c[1] * idet; - /*2*/ *dest++ = -_c[2] * idet; - /*3*/ *dest++ = _c[0] * idet; - /*4*/ *dest++ = -_c[4] * d._c[0] - _c[5] * d._c[2]; - /*5*/ *dest = -_c[4] * d._c[1] - _c[5] * d._c[3]; - - } else { - d.set_identity(); - } - - return d; -} - - - - - -/** - * Set this matrix to Identity - */ -void Matrix::set_identity() -{ - NR::Coord *dest = _c; - - *dest++ = 1.0; //0 - *dest++ = 0.0; //1 - *dest++ = 0.0; //2 - *dest++ = 1.0; //3 - // translation - *dest++ = 0.0; //4 - *dest = 0.0; //5 -} - - - - - -/** - * return an Identity matrix - */ -Matrix identity() -{ - Matrix ret(1.0, 0.0, - 0.0, 1.0, - 0.0, 0.0); - return ret; -} - - - - - -/** - * - */ -Matrix from_basis(Point const x_basis, Point const y_basis, Point const offset) -{ - Matrix const ret(x_basis[X], y_basis[X], - x_basis[Y], y_basis[Y], - offset[X], offset[Y]); - return ret; -} - - - - -/** - * Returns a rotation matrix corresponding by the specified angle (in radians) about the origin. - * - * \see NR::rotate_degrees - * - * Angle direction in Inkscape code: If you use the traditional mathematics convention that y - * increases upwards, then positive angles are anticlockwise as per the mathematics convention. If - * you take the common non-mathematical convention that y increases downwards, then positive angles - * are clockwise, as is common outside of mathematics. - */ -rotate::rotate(NR::Coord const theta) : - vec(cos(theta), - sin(theta)) -{ -} - - - - - -/** - * Return the determinant of the Matrix - */ -NR::Coord Matrix::det() const -{ - return _c[0] * _c[3] - _c[1] * _c[2]; -} - - - - - -/** - * Return the scalar of the descriminant of the Matrix - */ -NR::Coord Matrix::descrim2() const -{ - return fabs(det()); -} - - - - - -/** - * Return the descriminant of the Matrix - */ -NR::Coord Matrix::descrim() const -{ - return sqrt(descrim2()); -} - - - - - -/** - * - */ -bool Matrix::is_translation(Coord const eps) const { - return ( fabs(_c[0] - 1.0) < eps && - fabs(_c[3] - 1.0) < eps && - fabs(_c[1]) < eps && - fabs(_c[2]) < eps ); -} - - -/** - * - */ -bool Matrix::is_scale(Coord const eps) const { - return ( (fabs(_c[0] - 1.0) > eps || fabs(_c[3] - 1.0) > eps) && - fabs(_c[1]) < eps && - fabs(_c[2]) < eps ); -} - - -/** - * - */ -bool Matrix::is_rotation(Coord const eps) const { - return ( fabs(_c[1]) > eps && - fabs(_c[2]) > eps && - fabs(_c[1] + _c[2]) < 2 * eps); -} - - - - - -/** - * test whether the matrix is the identity matrix (true). (2geom's Matrix::isIdentity() does the same) - */ -bool Matrix::test_identity() const { - return matrix_equalp(*this, NR_MATRIX_IDENTITY, NR_EPSILON); -} - - - - - -/** - * calculates the descriminant of the matrix. (Geom::Coord Matrix::descrim() does the same) - */ -double expansion(Matrix const &m) { - return sqrt(fabs(m.det())); -} - - - - - -/** - * - */ -bool transform_equalp(Matrix const &m0, Matrix const &m1, NR::Coord const epsilon) { - return - NR_DF_TEST_CLOSE(m0[0], m1[0], epsilon) && - NR_DF_TEST_CLOSE(m0[1], m1[1], epsilon) && - NR_DF_TEST_CLOSE(m0[2], m1[2], epsilon) && - NR_DF_TEST_CLOSE(m0[3], m1[3], epsilon); -} - - - - - -/** - * - */ -bool translate_equalp(Matrix const &m0, Matrix const &m1, NR::Coord const epsilon) { - return NR_DF_TEST_CLOSE(m0[4], m1[4], epsilon) && NR_DF_TEST_CLOSE(m0[5], m1[5], epsilon); -} - - - - - -/** - * - */ -bool matrix_equalp(Matrix const &m0, Matrix const &m1, NR::Coord const epsilon) { - return transform_equalp(m0, m1, epsilon) && translate_equalp(m0, m1, epsilon); -} - - - -} //namespace NR - - - -/* - 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 : diff --git a/src/libnr/nr-matrix.h b/src/libnr/nr-matrix.h deleted file mode 100644 index 5d62dfafe..000000000 --- a/src/libnr/nr-matrix.h +++ /dev/null @@ -1,313 +0,0 @@ -#ifndef __NR_MATRIX_H__ -#define __NR_MATRIX_H__ - -/** \file - * Definition of NR::Matrix type. - * - * \note Operator functions (e.g. Matrix * Matrix etc.) are mostly in - * libnr/nr-matrix-ops.h. See end of file for discussion. - * - * Main authors: - * Lauris Kaplinski <lauris@kaplinski.com>: - * Original NRMatrix definition and related macros. - * - * Nathan Hurst <njh@mail.csse.monash.edu.au>: - * NR::Matrix class version of the above. - * - * This code is in public domain. - */ - -#include <glib.h> // g_assert() -#include <glib/gmessages.h> - -#include "libnr/nr-coord.h" -#include "libnr/nr-values.h" -#include <libnr/nr-rotate.h> -#include <libnr/nr-scale.h> -#include <libnr/nr-translate.h> -#include <2geom/affine.h> - -namespace NR { - -/** - * The Matrix class. - * - * For purposes of multiplication, points should be thought of as row vectors - * - * p = ( p[X] p[Y] 1 ) - * - * to be right-multiplied by transformation matrices - * \verbatim - c[] = | c[0] c[1] 0 | - | c[2] c[3] 0 | - | c[4] c[5] 1 | \endverbatim - * - * (so the columns of the matrix correspond to the columns (elements) of the result, - * and the rows of the matrix correspond to columns (elements) of the "input"). - */ -class Matrix { - - - public: - - /** - * Various forms of constructor - */ - - /** - * - */ - explicit Matrix() { } - - - /** - * - */ - Matrix(Matrix const &m) { - - NR::Coord const *src = m._c; - NR::Coord *dest = _c; - - *dest++ = *src++; //0 - *dest++ = *src++; //1 - *dest++ = *src++; //2 - *dest++ = *src++; //3 - *dest++ = *src++; //4 - *dest = *src ; //5 - - } - - - Matrix(Geom::Affine const &m) { - NR::Coord *dest = _c; - - *dest++ = m[0]; - *dest++ = m[1]; - *dest++ = m[2]; - *dest++ = m[3]; - *dest++ = m[4]; - *dest = m[5]; - } - - /** - * - */ - Matrix(double c0, double c1, - double c2, double c3, - double c4, double c5) { - - NR::Coord *dest = _c; - - *dest++ = c0; //0 - *dest++ = c1; //1 - *dest++ = c2; //2 - *dest++ = c3; //3 - *dest++ = c4; //4 - *dest = c5; //5 - - } - - - - /** - * - */ - Matrix &operator=(Matrix const &m) { - - NR::Coord const *src = m._c; - NR::Coord *dest = _c; - - *dest++ = *src++; //0 - *dest++ = *src++; //1 - *dest++ = *src++; //2 - *dest++ = *src++; //3 - *dest++ = *src++; //4 - *dest = *src ; //5 - - return *this; - } - - - - - /** - * - */ - explicit Matrix(scale const &sm) { - - NR::Coord *dest = _c; - - *dest++ = sm[X]; //0 - *dest++ = 0.0; //1 - *dest++ = 0.0; //2 - *dest++ = sm[Y]; //3 - *dest++ = 0.0; //4 - *dest = 0.0; //5 - - } - - - - - - - /** - * - */ - explicit Matrix(rotate const &r) { - - NR::Coord *dest = _c; - - *dest++ = r.vec[X]; //0 - *dest++ = r.vec[Y]; //1 - *dest++ = -r.vec[Y]; //2 - *dest++ = r.vec[X]; //3 - *dest++ = 0.0; //4 - *dest = 0.0; //5 - - } - - - - - /** - * - */ - explicit Matrix(translate const &tm) { - - NR::Coord *dest = _c; - - *dest++ = 1.0; //0 - *dest++ = 0.0; //1 - *dest++ = 0.0; //2 - *dest++ = 1.0; //3 - *dest++ = tm[X]; //4 - *dest = tm[Y]; //5 - } - - - /** - * - */ - bool test_identity() const; - - - /** - * - */ - bool is_translation(Coord const eps = 1e-6) const; - - /** - * - */ - bool is_scale(Coord const eps = 1e-6) const; - - /** - * - */ - bool is_rotation(Coord const eps = 1e-6) const; - - - /** - * - */ - Matrix inverse() const; - - - - /** - * - */ - inline Coord &operator[](int const i) { - return _c[i]; - } - - - - /** - * - */ - inline Coord operator[](int const i) const { - return _c[i]; - } - - inline operator Geom::Affine() const { - return Geom::Affine(_c[0], _c[1], _c[2], _c[3], _c[4], _c[5]); - } - - /** - * - */ - void set_identity(); - - /** - * - */ - Coord det() const; - - - /** - * - */ - Coord descrim2() const; - - - /** - * - */ - Coord descrim() const; - - - private: - - - NR::Coord _c[6]; -}; - -/** A function to print out the Matrix (for debugging) */ -inline std::ostream &operator<< (std::ostream &out_file, const NR::Matrix &m) { - out_file << "A: " << m[0] << " C: " << m[2] << " E: " << m[4] << "\n"; - out_file << "B: " << m[1] << " D: " << m[3] << " F: " << m[5] << "\n"; - return out_file; -} - -} /* namespace NR */ - - - - - - - -/** \note - * Discussion of splitting up nr-matrix.h into lots of little files: - * - * Advantages: - * - * - Reducing amount of recompilation necessary when anything changes. - * - * - Hopefully also reducing compilation time by reducing the number of inline - * function definitions encountered by the compiler for a given .o file. - * (No timing comparisons done yet. On systems without much memory available - * for caching, this may be outweighed by additional I/O costs.) - * - * Disadvantages: - * - * - More #include lines necessary per file. If a compile fails due to - * not having all the necessary #include lines, then the developer needs - * to spend some time working out what #include to add. - */ - -#endif /* !__NR_MATRIX_H__ */ - - -/* - 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 : diff --git a/src/libnr/nr-maybe.h b/src/libnr/nr-maybe.h deleted file mode 100644 index 1413f69d2..000000000 --- a/src/libnr/nr-maybe.h +++ /dev/null @@ -1,201 +0,0 @@ -#ifndef __NR_MAYBE_H__ -#define __NR_MAYBE_H__ - -/* - * Nullable values for C++ - * - * Copyright 2004, 2007 MenTaLguY <mental@rydia.net> - * - * This code is licensed under the GNU GPL; see COPYING for more information. - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include <stdexcept> -#include <string> -#include <algorithm> - -namespace NR { - -class IsNothing : public std::domain_error { -public: - IsNothing() : domain_error(std::string("Is nothing")) {} -}; - -struct Nothing {}; - -template <typename T> -class MaybeStorage { -public: - MaybeStorage() : _is_nothing(true) {} - MaybeStorage(T const &value) - : _value(value), _is_nothing(false) {} - - bool is_nothing() const { return _is_nothing; } - T &value() { return _value; } - T const &value() const { return _value; } - -private: - T _value; - bool _is_nothing; -}; - -template <typename T> -class Maybe { -public: - Maybe() {} - Maybe(Nothing) {} - Maybe(T const &t) : _storage(t) {} - Maybe(Maybe const &m) : _storage(m._storage) {} - - template <typename T2> - Maybe(Maybe<T2> const &m) { - if (m) { - _storage = *m; - } - } - - template <typename T2> - Maybe(Maybe<T2 const &> m) { - if (m) { - _storage = *m; - } - } - - operator bool() const { return !_storage.is_nothing(); } - - T const &operator*() const throw(IsNothing) { - if (_storage.is_nothing()) { - throw IsNothing(); - } else { - return _storage.value(); - } - } - T &operator*() throw(IsNothing) { - if (_storage.is_nothing()) { - throw IsNothing(); - } else { - return _storage.value(); - } - } - - T const *operator->() const throw(IsNothing) { - if (_storage.is_nothing()) { - throw IsNothing(); - } else { - return &_storage.value(); - } - } - T *operator->() throw(IsNothing) { - if (_storage.is_nothing()) { - throw IsNothing(); - } else { - return &_storage.value(); - } - } - - template <typename T2> - bool operator==(Maybe<T2> const &other) const { - bool is_nothing = _storage.is_nothing(); - if ( is_nothing || !other ) { - return is_nothing && !other; - } else { - return _storage.value() == *other; - } - } - template <typename T2> - bool operator!=(Maybe<T2> const &other) const { - bool is_nothing = _storage.is_nothing(); - if ( is_nothing || !other ) { - return !is_nothing || other; - } else { - return _storage.value() != *other; - } - } - -private: - MaybeStorage<T> _storage; -}; - -template <typename T> -class Maybe<T &> { -public: - Maybe() : _ref(NULL) {} - Maybe(Nothing) : _ref(NULL) {} - Maybe(T &t) : _ref(&t) {} - - template <typename T2> - Maybe(Maybe<T2> const &m) { - if (m) { - _ref = &*m; - } - } - - template <typename T2> - Maybe(Maybe<T2 &> m) { - if (m) { - _ref = *m; - } - } - - template <typename T2> - Maybe(Maybe<T2 const &> m) { - if (m) { - _ref = *m; - } - } - - operator bool() const { return _ref; } - - T &operator*() const throw(IsNothing) { - if (!_ref) { - throw IsNothing(); - } else { - return *_ref; - } - } - T *operator->() const throw(IsNothing) { - if (!_ref) { - throw IsNothing(); - } else { - return _ref; - } - } - - template <typename T2> - bool operator==(Maybe<T2> const &other) const { - if ( !_ref || !other ) { - return !_ref && !other; - } else { - return *_ref == *other; - } - } - template <typename T2> - bool operator!=(Maybe <T2> const &other) const { - if ( !_ref || !other ) { - return _ref || other; - } else { - return *_ref != *other; - } - } - -private: - T *_ref; -}; - -} /* namespace NR */ - -#endif - -/* - 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 : diff --git a/src/libnr/nr-path-code.h b/src/libnr/nr-path-code.h deleted file mode 100644 index cc174d73b..000000000 --- a/src/libnr/nr-path-code.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef SEEN_LIBNR_NR_PATH_CODE_H -#define SEEN_LIBNR_NR_PATH_CODE_H - -/** \file - * NRPathcode enum definition - */ - -typedef enum { - NR_MOVETO, ///< Start of closed subpath - NR_MOVETO_OPEN, ///< Start of open subpath - NR_CURVETO, ///< Bezier curve segment - NR_LINETO, ///< Line segment - NR_END ///< End record -} NRPathcode; - - -#endif /* !SEEN_LIBNR_NR_PATH_CODE_H */ - -/* - 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 : diff --git a/src/libnr/nr-pixblock-line.cpp b/src/libnr/nr-pixblock-line.cpp deleted file mode 100644 index eb8b404b4..000000000 --- a/src/libnr/nr-pixblock-line.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#define __NR_PIXBLOCK_LINE_C__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * This code is in public domain - */ - -#include <libnr/nr-pixops.h> -#include <libnr/nr-pixblock-pixel.h> - -void -nr_pixblock_draw_line_rgba32 (NRPixBlock *d, long x0, long y0, long x1, long y1, short /*first*/, unsigned long rgba) -{ - long deltax, deltay, xinc1, xinc2, yinc1, yinc2; - long den, num, numadd, numpixels; - long x, y, curpixel; - /* Pixblock */ - int dbpp; - NRPixBlock spb; - unsigned char *spx; - - if (x1 >= x0) { - deltax = x1 - x0; - xinc1 = 1; - xinc2 = 1; - } else { - deltax = x0 - x1; - xinc1 = -1; - xinc2 = -1; - } - - if (y1 >= y0) { - deltay = y1 - y0; - yinc1 = 1; - yinc2 = 1; - } else { - deltay = y0 - y1; - yinc1 = -1; - yinc2 = -1; - } - - if (deltax >= deltay) { - xinc1 = 0; - yinc2 = 0; - den = deltax; - num = deltax / 2; - numadd = deltay; - numpixels = deltax; - } else { - xinc2 = 0; - yinc1 = 0; - den = deltay; - num = deltay / 2; - numadd = deltax; - numpixels = deltay; - } - - /* We can be quite sure 1x1 pixblock is TINY */ - nr_pixblock_setup_fast (&spb, NR_PIXBLOCK_MODE_R8G8B8A8N, 0, 0, 1, 1, 0); - spb.empty = 0; - spx = NR_PIXBLOCK_PX (&spb); - spx[0] = NR_RGBA32_R (rgba); - spx[1] = NR_RGBA32_G (rgba); - spx[2] = NR_RGBA32_B (rgba); - spx[3] = NR_RGBA32_A (rgba); - - dbpp = NR_PIXBLOCK_BPP (d); - - x = x0; - y = y0; - - for (curpixel = 0; curpixel <= numpixels; curpixel++) { - if ((x >= d->area.x0) && (y >= d->area.y0) && (x < d->area.x1) && (y < d->area.y1)) { - nr_compose_pixblock_pixblock_pixel (d, NR_PIXBLOCK_PX (d) + (y - d->area.y0) * d->rs + (x - d->area.x0) * dbpp, &spb, spx); - } - num += numadd; - if (num >= den) { - num -= den; - x += xinc1; - y += yinc1; - } - x += xinc2; - y += yinc2; - } - - nr_pixblock_release (&spb); -} - diff --git a/src/libnr/nr-pixblock-line.h b/src/libnr/nr-pixblock-line.h deleted file mode 100644 index cebab31d8..000000000 --- a/src/libnr/nr-pixblock-line.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __NR_PIXBLOCK_LINE_H__ -#define __NR_PIXBLOCK_LINE_H__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * This code is in public domain - */ - -#include <libnr/nr-pixblock.h> - -void nr_pixblock_draw_line_rgba32 (NRPixBlock *d, long x0, long y0, long x1, long y1, short first, unsigned long rgba); - -#endif - -/* - 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 : diff --git a/src/libnr/nr-pixblock-pattern.cpp b/src/libnr/nr-pixblock-pattern.cpp deleted file mode 100644 index aa3246297..000000000 --- a/src/libnr/nr-pixblock-pattern.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#define __NR_PIXBLOCK_PATTERN_C__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * This code is in public domain - */ - - -#include <glib/gmem.h> -#include "nr-pixops.h" -#include "nr-pixblock-pattern.h" - -#define NR_NOISE_SIZE 1024 - -void -nr_pixblock_render_gray_noise (NRPixBlock *pb, NRPixBlock *mask) -{ - static unsigned char *noise = NULL; - static unsigned int seed = 0; - unsigned int v; - NRRectL clip; - int x, y, bpp; - - if (mask) { - if (mask->empty) return; - nr_rect_l_intersect (&clip, &pb->area, &mask->area); - if (nr_rect_l_test_empty(clip)) return; - } else { - clip = pb->area; - } - - if (!noise) { - int i; - noise = g_new (unsigned char, NR_NOISE_SIZE); - for (i = 0; i < NR_NOISE_SIZE; i++) noise[i] = (rand () / (RAND_MAX >> 8)) & 0xff; - } - - bpp = NR_PIXBLOCK_BPP (pb); - - v = (rand () / (RAND_MAX >> 8)) & 0xff; - - if (mask) { - for (y = clip.y0; y < clip.y1; y++) { - unsigned char *d, *m; - d = NR_PIXBLOCK_PX (pb) + (y - pb->area.y0) * pb->rs + (clip.x0 - pb->area.x0) * bpp; - m = NR_PIXBLOCK_PX (mask) + (y - mask->area.y0) * pb->rs + (clip.x0 - mask->area.x0); - for (x = clip.x0; x < clip.x1; x++) { - v = v ^ noise[seed]; - switch (pb->mode) { - case NR_PIXBLOCK_MODE_A8: - d[0] = NR_COMPOSEA_111(m[0], d[0]); - break; - case NR_PIXBLOCK_MODE_R8G8B8: - d[0] = NR_COMPOSEN11_1111 (v, m[0], d[0]); - d[1] = NR_COMPOSEN11_1111 (v, m[0], d[1]); - d[2] = NR_COMPOSEN11_1111 (v, m[0], d[2]); - break; - case NR_PIXBLOCK_MODE_R8G8B8A8N: - if (m[0] != 0) { - unsigned int ca; - ca = NR_COMPOSEA_112(m[0], d[3]); - d[0] = NR_COMPOSENNN_111121 (v, m[0], d[0], d[3], ca); - d[1] = NR_COMPOSENNN_111121 (v, m[0], d[1], d[3], ca); - d[2] = NR_COMPOSENNN_111121 (v, m[0], d[2], d[3], ca); - d[3] = NR_NORMALIZE_21(ca); - } - break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: - d[0] = NR_COMPOSENPP_1111 (v, m[0], d[0]); - d[1] = NR_COMPOSENPP_1111 (v, m[0], d[1]); - d[2] = NR_COMPOSENPP_1111 (v, m[0], d[2]); - d[3] = NR_COMPOSEA_111(d[3], m[0]); - break; - default: - break; - } - d += bpp; - m += 1; - if (++seed >= NR_NOISE_SIZE) { - int i; - i = (rand () / (RAND_MAX / NR_NOISE_SIZE)) % NR_NOISE_SIZE; - noise[i] ^= v; - seed = i % (NR_NOISE_SIZE >> 2); - } - } - } - } else { - for (y = clip.y0; y < clip.y1; y++) { - unsigned char *d; - d = NR_PIXBLOCK_PX (pb) + (y - pb->area.y0) * pb->rs + (clip.x0 - pb->area.x0) * bpp; - for (x = clip.x0; x < clip.x1; x++) { - v = v ^ noise[seed]; - switch (pb->mode) { - case NR_PIXBLOCK_MODE_A8: - d[0] = 255; - break; - case NR_PIXBLOCK_MODE_R8G8B8: - d[0] = v; - d[1] = v; - d[2] = v; - break; - case NR_PIXBLOCK_MODE_R8G8B8A8N: - case NR_PIXBLOCK_MODE_R8G8B8A8P: - d[0] = v; - d[1] = v; - d[2] = v; - d[3] = 255; - default: - break; - } - d += bpp; - if (++seed >= NR_NOISE_SIZE) { - int i; - i = (rand () / (RAND_MAX / NR_NOISE_SIZE)) % NR_NOISE_SIZE; - noise[i] ^= v; - seed = i % (NR_NOISE_SIZE >> 2); - } - } - } - } - - pb->empty = 0; -} diff --git a/src/libnr/nr-pixblock-pattern.h b/src/libnr/nr-pixblock-pattern.h deleted file mode 100644 index a79a39f13..000000000 --- a/src/libnr/nr-pixblock-pattern.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __NR_PIXBLOCK_PATTERN_H__ -#define __NR_PIXBLOCK_PATTERN_H__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * This code is in public domain - */ - -#include <libnr/nr-pixblock.h> - -void nr_pixblock_render_gray_noise (NRPixBlock *pb, NRPixBlock *mask); - -#endif - -/* - 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 : diff --git a/src/libnr/nr-pixblock-pixel.cpp b/src/libnr/nr-pixblock-pixel.cpp deleted file mode 100644 index 109ed69dc..000000000 --- a/src/libnr/nr-pixblock-pixel.cpp +++ /dev/null @@ -1,230 +0,0 @@ -#define __NR_PIXBLOCK_PIXEL_C__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * This code is in public domain - */ - -#include "nr-pixops.h" -#include "nr-pixblock-pixel.h" - -void -nr_compose_pixblock_pixblock_pixel (NRPixBlock *dpb, unsigned char *d, const NRPixBlock *spb, const unsigned char *s) -{ - if (spb->empty) return; - - if (dpb->empty) { - /* Empty destination */ - switch (dpb->mode) { - case NR_PIXBLOCK_MODE_A8: - switch (spb->mode) { - case NR_PIXBLOCK_MODE_A8: - break; - case NR_PIXBLOCK_MODE_R8G8B8: - d[0] = 255; - break; - case NR_PIXBLOCK_MODE_R8G8B8A8N: - d[0] = s[3]; - break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: - d[0] = s[3]; - break; - default: - break; - } - break; - case NR_PIXBLOCK_MODE_R8G8B8: - switch (spb->mode) { - case NR_PIXBLOCK_MODE_A8: - break; - case NR_PIXBLOCK_MODE_R8G8B8: - d[0] = s[0]; - d[1] = s[1]; - d[2] = s[2]; - break; - case NR_PIXBLOCK_MODE_R8G8B8A8N: - d[0] = NR_COMPOSEN11_1111 (s[0], s[3], 255); - d[1] = NR_COMPOSEN11_1111 (s[1], s[3], 255); - d[2] = NR_COMPOSEN11_1111 (s[2], s[3], 255); - break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: - d[0] = NR_COMPOSEP11_1111 (s[0], s[3], 255); - d[1] = NR_COMPOSEP11_1111 (s[1], s[3], 255); - d[2] = NR_COMPOSEP11_1111 (s[2], s[3], 255); - break; - default: - break; - } - break; - case NR_PIXBLOCK_MODE_R8G8B8A8N: - switch (spb->mode) { - case NR_PIXBLOCK_MODE_A8: - break; - case NR_PIXBLOCK_MODE_R8G8B8: - d[0] = s[0]; - d[1] = s[1]; - d[2] = s[2]; - d[3] = 255; - break; - case NR_PIXBLOCK_MODE_R8G8B8A8N: - d[0] = s[0]; - d[1] = s[1]; - d[2] = s[2]; - d[3] = s[3]; - break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: - if (s[3] == 0) { - d[0] = 255; - d[1] = 255; - d[2] = 255; - } else { - d[0] = NR_DEMUL_111(s[0], s[3]); - d[1] = NR_DEMUL_111(s[0], s[3]); - d[2] = NR_DEMUL_111(s[0], s[3]); - } - d[3] = s[3]; - break; - default: - break; - } - break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: - switch (spb->mode) { - case NR_PIXBLOCK_MODE_A8: - break; - case NR_PIXBLOCK_MODE_R8G8B8: - d[0] = s[0]; - d[1] = s[1]; - d[2] = s[2]; - d[3] = 255; - break; - case NR_PIXBLOCK_MODE_R8G8B8A8N: - d[0] = NR_PREMUL_111 (s[0], s[3]); - d[1] = NR_PREMUL_111 (s[1], s[3]); - d[2] = NR_PREMUL_111 (s[2], s[3]); - d[3] = s[3]; - break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: - d[0] = s[0]; - d[1] = s[1]; - d[2] = s[2]; - d[3] = s[3]; - break; - default: - break; - } - break; - default: - break; - } - } else { - /* Image destination */ - switch (dpb->mode) { - case NR_PIXBLOCK_MODE_A8: - switch (spb->mode) { - case NR_PIXBLOCK_MODE_A8: - break; - case NR_PIXBLOCK_MODE_R8G8B8: - d[0] = 255; - break; - case NR_PIXBLOCK_MODE_R8G8B8A8N: - d[0] = NR_COMPOSEA_111(s[3], d[0]); - break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: - d[0] = NR_COMPOSEA_111(s[3], d[0]); - break; - default: - break; - } - break; - case NR_PIXBLOCK_MODE_R8G8B8: - switch (spb->mode) { - case NR_PIXBLOCK_MODE_A8: - break; - case NR_PIXBLOCK_MODE_R8G8B8: - d[0] = s[0]; - d[1] = s[1]; - d[2] = s[2]; - break; - case NR_PIXBLOCK_MODE_R8G8B8A8N: - d[0] = NR_COMPOSEN11_1111 (s[0], s[3], d[0]); - d[1] = NR_COMPOSEN11_1111 (s[1], s[3], d[1]); - d[2] = NR_COMPOSEN11_1111 (s[2], s[3], d[2]); - break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: - d[0] = NR_COMPOSEP11_1111 (s[0], s[3], d[0]); - d[1] = NR_COMPOSEP11_1111 (s[1], s[3], d[1]); - d[2] = NR_COMPOSEP11_1111 (s[2], s[3], d[2]); - break; - default: - break; - } - break; - case NR_PIXBLOCK_MODE_R8G8B8A8N: - switch (spb->mode) { - case NR_PIXBLOCK_MODE_A8: - break; - case NR_PIXBLOCK_MODE_R8G8B8: - d[0] = s[0]; - d[1] = s[1]; - d[2] = s[2]; - break; - case NR_PIXBLOCK_MODE_R8G8B8A8N: - if (s[3] != 0) { - unsigned int ca; - ca = NR_COMPOSEA_112(s[3], d[3]); - d[0] = NR_COMPOSENNN_111121 (s[0], s[3], d[0], d[3], ca); - d[1] = NR_COMPOSENNN_111121 (s[1], s[3], d[1], d[3], ca); - d[2] = NR_COMPOSENNN_111121 (s[2], s[3], d[2], d[3], ca); - d[3] = NR_NORMALIZE_21(ca); - } - break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: - if (s[3] != 0) { - unsigned int ca; - ca = NR_COMPOSEA_112(s[3], d[3]); - d[0] = NR_COMPOSEPNN_111121 (s[0], s[3], d[0], d[3], ca); - d[1] = NR_COMPOSEPNN_111121 (s[1], s[3], d[0], d[3], ca); - d[2] = NR_COMPOSEPNN_111121 (s[2], s[3], d[0], d[3], ca); - d[3] = NR_NORMALIZE_21(ca); - } - break; - default: - break; - } - break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: - switch (spb->mode) { - case NR_PIXBLOCK_MODE_A8: - break; - case NR_PIXBLOCK_MODE_R8G8B8: - d[0] = s[0]; - d[1] = s[1]; - d[2] = s[2]; - break; - case NR_PIXBLOCK_MODE_R8G8B8A8N: - d[0] = NR_COMPOSENPP_1111 (s[0], s[3], d[0]); - d[1] = NR_COMPOSENPP_1111 (s[1], s[3], d[1]); - d[2] = NR_COMPOSENPP_1111 (s[2], s[3], d[2]); - d[3] = NR_COMPOSEA_111(s[3], d[3]); - break; - case NR_PIXBLOCK_MODE_R8G8B8A8P: - d[0] = NR_COMPOSEPPP_1111 (s[0], s[3], d[0]); - d[1] = NR_COMPOSEPPP_1111 (s[1], s[3], d[1]); - d[2] = NR_COMPOSEPPP_1111 (s[2], s[3], d[2]); - d[3] = NR_COMPOSEA_111(s[3], d[3]); - break; - default: - break; - } - break; - default: - break; - } - } -} - diff --git a/src/libnr/nr-pixblock-pixel.h b/src/libnr/nr-pixblock-pixel.h deleted file mode 100644 index da64aee4c..000000000 --- a/src/libnr/nr-pixblock-pixel.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __NR_PIXBLOCK_PIXEL_H__ -#define __NR_PIXBLOCK_PIXEL_H__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * This code is in public domain - */ - -#include <libnr/nr-pixblock.h> - -void nr_compose_pixblock_pixblock_pixel (NRPixBlock *dpb, unsigned char *d, const NRPixBlock *spb, const unsigned char *s); - -#endif - -/* - 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 : diff --git a/src/libnr/nr-pixblock.cpp b/src/libnr/nr-pixblock.cpp deleted file mode 100644 index b95d8db8d..000000000 --- a/src/libnr/nr-pixblock.cpp +++ /dev/null @@ -1,465 +0,0 @@ -#define __NR_PIXBLOCK_C__ - -/** \file - * \brief Allocation/Setup of NRPixBlock objects. Pixel store functions. - * - * Authors: - * (C) 1999-2002 Lauris Kaplinski <lauris@kaplinski.com> - * 2008, Jasper van de Gronde <th.v.d.gonde@hccnet.nl> - * - * This code is in the Public Domain - */ - -#include <cstring> -#include <string> -#include <string.h> -#include <glib/gmem.h> -#include "nr-pixblock.h" - -/// Size of buffer that needs no allocation (default 4). -#define NR_TINY_MAX sizeof (unsigned char *) - -/** - * Pixbuf initialisation using homegrown memory handling ("pixelstore"). - * - * Pixbuf sizes are differentiated into tiny, <4K, <16K, <64K, and more, - * with each type having its own method of memory handling. After allocating - * memory, the buffer is cleared if the clear flag is set. Intended to - * reduce memory fragmentation. - * \param pb Pointer to the pixbuf struct. - * \param mode Indicates grayscale/RGB/RGBA. - * \param clear True if buffer should be cleared. - * \pre x1>=x0 && y1>=y0 && pb!=NULL - */ -void -nr_pixblock_setup_fast (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear) -{ - int w, h, bpp; - size_t size; - - w = x1 - x0; - h = y1 - y0; - bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4; - - guint64 sizel = (guint64)bpp * (guint64)w * (guint64)h; - - if(sizel > (guint64)G_MAXSIZE) { - g_warning ("the requested memory exceeds the system limit"); - return; - } - - size = bpp * w * h; - - if (size <= NR_TINY_MAX) { - pb->size = NR_PIXBLOCK_SIZE_TINY; - if (clear) memset (pb->data.p, 0x0, size); - } else if (size <= 4096) { - pb->size = NR_PIXBLOCK_SIZE_4K; - pb->data.px = nr_pixelstore_4K_new (clear, 0x0); - } else if (size <= 16384) { - pb->size = NR_PIXBLOCK_SIZE_16K; - pb->data.px = nr_pixelstore_16K_new (clear, 0x0); - } else if (size <= 65536) { - pb->size = NR_PIXBLOCK_SIZE_64K; - pb->data.px = nr_pixelstore_64K_new (clear, 0x0); - } else if (size <= 262144) { - pb->size = NR_PIXBLOCK_SIZE_256K; - pb->data.px = nr_pixelstore_256K_new (clear, 0x0); - } else if (size <= 1048576) { - pb->size = NR_PIXBLOCK_SIZE_1M; - pb->data.px = nr_pixelstore_1M_new (clear, 0x0); - } else { - pb->size = NR_PIXBLOCK_SIZE_BIG; - pb->data.px = NULL; - if (size > 100000000) { // Don't even try to allocate more than 100Mb (5000x5000 RGBA - // pixels). It'll just bog the system down even if successful. FIXME: - // Can anyone suggest something better than the magic number? - g_warning ("%lu bytes requested for pixel buffer, this will slow down the system.", (long unsigned) size); - // do not quit here, let the system decide for RAM usage - // return; - } - pb->data.px = g_try_new (unsigned char, size); - if (pb->data.px == NULL) { // memory allocation failed - g_warning ("Could not allocate %lu bytes for pixel buffer!", (long unsigned) size); - return; - } - if (clear) memset (pb->data.px, 0x0, size); - } - - pb->mode = mode; - pb->empty = 1; - pb->visible_area.x0 = pb->area.x0 = x0; - pb->visible_area.y0 = pb->area.y0 = y0; - pb->visible_area.x1 = pb->area.x1 = x1; - pb->visible_area.y1 = pb->area.y1 = y1; - pb->rs = bpp * w; -} - -/** - * Pixbuf initialisation using g_new. - * - * After allocating memory, the buffer is cleared if the clear flag is set. - * \param pb Pointer to the pixbuf struct. - * \param mode Indicates grayscale/RGB/RGBA. - * \param clear True if buffer should be cleared. - * \pre x1>=x0 && y1>=y0 && pb!=NULL - FIXME: currently unused except for nr_pixblock_new and pattern tiles, replace with _fast and delete? - */ -void -nr_pixblock_setup (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear) -{ - int w, h, bpp; - size_t size; - - w = x1 - x0; - h = y1 - y0; - bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4; - - size = bpp * w * h; - - if (size <= NR_TINY_MAX) { - pb->size = NR_PIXBLOCK_SIZE_TINY; - if (clear) memset (pb->data.p, 0x0, size); - } else { - pb->size = NR_PIXBLOCK_SIZE_BIG; - pb->data.px = g_new (unsigned char, size); - if (clear) memset (pb->data.px, 0x0, size); - } - - pb->mode = mode; - pb->empty = 1; - pb->visible_area.x0 = pb->area.x0 = x0; - pb->visible_area.y0 = pb->area.y0 = y0; - pb->visible_area.x1 = pb->area.x1 = x1; - pb->visible_area.y1 = pb->area.y1 = y1; - pb->rs = bpp * w; -} - -/** - * Pixbuf initialisation with preset values. - * - * After copying all parameters into the NRPixBlock struct, the pixel buffer is cleared if the clear flag is set. - * \param pb Pointer to the pixbuf struct. - * \param mode Indicates grayscale/RGB/RGBA. - * \param clear True if buffer should be cleared. - * \pre x1>=x0 && y1>=y0 && pb!=NULL - */ -void -nr_pixblock_setup_extern (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, unsigned char *px, int rs, bool empty, bool clear) -{ - int w, bpp; - - w = x1 - x0; - bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4; - - pb->size = NR_PIXBLOCK_SIZE_STATIC; - pb->mode = mode; - pb->empty = empty; - pb->visible_area.x0 = pb->area.x0 = x0; - pb->visible_area.y0 = pb->area.y0 = y0; - pb->visible_area.x1 = pb->area.x1 = x1; - pb->visible_area.y1 = pb->area.y1 = y1; - pb->data.px = px; - pb->rs = rs; - - g_assert (pb->data.px != NULL); - if (clear) { - if (rs == bpp * w) { - /// \todo How do you recognise if - /// px was an uncleared tiny buffer? - if (pb->data.px) - memset (pb->data.px, 0x0, bpp * (y1 - y0) * w); - } else { - int y; - for (y = y0; y < y1; y++) { - memset (pb->data.px + (y - y0) * rs, 0x0, bpp * w); - } - } - } -} - -/** - * Frees memory taken by pixel data in NRPixBlock. - * \param pb Pointer to pixblock. - * \pre pb and pb->data.px point to valid addresses. - * - * According to pb->size, one of the functions for freeing the pixelstore - * is called. May be called regardless of how pixbuf was set up. - */ -void -nr_pixblock_release (NRPixBlock *pb) -{ - switch (pb->size) { - case NR_PIXBLOCK_SIZE_TINY: - break; - case NR_PIXBLOCK_SIZE_4K: - nr_pixelstore_4K_free (pb->data.px); - break; - case NR_PIXBLOCK_SIZE_16K: - nr_pixelstore_16K_free (pb->data.px); - break; - case NR_PIXBLOCK_SIZE_64K: - nr_pixelstore_64K_free (pb->data.px); - break; - case NR_PIXBLOCK_SIZE_256K: - nr_pixelstore_256K_free (pb->data.px); - break; - case NR_PIXBLOCK_SIZE_1M: - nr_pixelstore_1M_free (pb->data.px); - break; - case NR_PIXBLOCK_SIZE_BIG: - g_free (pb->data.px); - break; - case NR_PIXBLOCK_SIZE_STATIC: - break; - default: - break; - } -} - -/** - * Allocates NRPixBlock and sets it up. - * - * \return Pointer to fresh pixblock. - * Calls g_new() and nr_pixblock_setup(). -FIXME: currently unused, delete? JG: Should be used more often! (To simplify memory management.) - */ -NRPixBlock * -nr_pixblock_new (NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear) -{ - NRPixBlock *pb; - - pb = g_new (NRPixBlock, 1); - if (!pb) return 0; - - nr_pixblock_setup (pb, mode, x0, y0, x1, y1, clear); - if (pb->size!=NR_PIXBLOCK_SIZE_TINY && !pb->data.px) { - g_free(pb); - return 0; - } - - return pb; -} - -/** - * Allocates NRPixBlock and sets it up. - * - * \return Pointer to fresh pixblock. - * Calls g_new() and nr_pixblock_setup(). - */ -NRPixBlock * -nr_pixblock_new_fast (NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear) -{ - NRPixBlock *pb; - - pb = g_new (NRPixBlock, 1); - if (!pb) return 0; - - nr_pixblock_setup_fast (pb, mode, x0, y0, x1, y1, clear); - if (pb->size!=NR_PIXBLOCK_SIZE_TINY && !pb->data.px) { - g_free(pb); - return 0; - } - - return pb; -} - -/** - * Frees all memory taken by pixblock. - * - * \return NULL - */ -NRPixBlock * -nr_pixblock_free (NRPixBlock *pb) -{ - nr_pixblock_release (pb); - - g_free (pb); - - return NULL; -} - -/* PixelStore operations */ - -#define NR_4K_BLOCK 32 -static unsigned char **nr_4K_px = NULL; -static unsigned int nr_4K_len = 0; -static unsigned int nr_4K_size = 0; - -unsigned char * -nr_pixelstore_4K_new (bool clear, unsigned char val) -{ - unsigned char *px; - - if (nr_4K_len != 0) { - nr_4K_len -= 1; - px = nr_4K_px[nr_4K_len]; - } else { - px = g_new (unsigned char, 4096); - } - - if (clear) memset (px, val, 4096); - - return px; -} - -void -nr_pixelstore_4K_free (unsigned char *px) -{ - if (nr_4K_len == nr_4K_size) { - nr_4K_size += NR_4K_BLOCK; - nr_4K_px = g_renew (unsigned char *, nr_4K_px, nr_4K_size); - } - - nr_4K_px[nr_4K_len] = px; - nr_4K_len += 1; -} - -#define NR_16K_BLOCK 32 -static unsigned char **nr_16K_px = NULL; -static unsigned int nr_16K_len = 0; -static unsigned int nr_16K_size = 0; - -unsigned char * -nr_pixelstore_16K_new (bool clear, unsigned char val) -{ - unsigned char *px; - - if (nr_16K_len != 0) { - nr_16K_len -= 1; - px = nr_16K_px[nr_16K_len]; - } else { - px = g_new (unsigned char, 16384); - } - - if (clear) memset (px, val, 16384); - - return px; -} - -void -nr_pixelstore_16K_free (unsigned char *px) -{ - if (nr_16K_len == nr_16K_size) { - nr_16K_size += NR_16K_BLOCK; - nr_16K_px = g_renew (unsigned char *, nr_16K_px, nr_16K_size); - } - - nr_16K_px[nr_16K_len] = px; - nr_16K_len += 1; -} - -#define NR_64K_BLOCK 32 -static unsigned char **nr_64K_px = NULL; -static unsigned int nr_64K_len = 0; -static unsigned int nr_64K_size = 0; - -unsigned char * -nr_pixelstore_64K_new (bool clear, unsigned char val) -{ - unsigned char *px; - - if (nr_64K_len != 0) { - nr_64K_len -= 1; - px = nr_64K_px[nr_64K_len]; - } else { - px = g_new (unsigned char, 65536); - } - - if (clear) memset (px, val, 65536); - - return px; -} - -void -nr_pixelstore_64K_free (unsigned char *px) -{ - if (nr_64K_len == nr_64K_size) { - nr_64K_size += NR_64K_BLOCK; - nr_64K_px = g_renew (unsigned char *, nr_64K_px, nr_64K_size); - } - - nr_64K_px[nr_64K_len] = px; - nr_64K_len += 1; -} - -#define NR_256K_BLOCK 32 -#define NR_256K 262144 -static unsigned char **nr_256K_px = NULL; -static unsigned int nr_256K_len = 0; -static unsigned int nr_256K_size = 0; - -unsigned char * -nr_pixelstore_256K_new (bool clear, unsigned char val) -{ - unsigned char *px; - - if (nr_256K_len != 0) { - nr_256K_len -= 1; - px = nr_256K_px[nr_256K_len]; - } else { - px = g_new (unsigned char, NR_256K); - } - - if (clear) memset (px, val, NR_256K); - - return px; -} - -void -nr_pixelstore_256K_free (unsigned char *px) -{ - if (nr_256K_len == nr_256K_size) { - nr_256K_size += NR_256K_BLOCK; - nr_256K_px = g_renew (unsigned char *, nr_256K_px, nr_256K_size); - } - - nr_256K_px[nr_256K_len] = px; - nr_256K_len += 1; -} - -#define NR_1M_BLOCK 32 -#define NR_1M 1048576 -static unsigned char **nr_1M_px = NULL; -static unsigned int nr_1M_len = 0; -static unsigned int nr_1M_size = 0; - -unsigned char * -nr_pixelstore_1M_new (bool clear, unsigned char val) -{ - unsigned char *px; - - if (nr_1M_len != 0) { - nr_1M_len -= 1; - px = nr_1M_px[nr_1M_len]; - } else { - px = g_new (unsigned char, NR_1M); - } - - if (clear) memset (px, val, NR_1M); - - return px; -} - -void -nr_pixelstore_1M_free (unsigned char *px) -{ - if (nr_1M_len == nr_1M_size) { - nr_1M_size += NR_1M_BLOCK; - nr_1M_px = g_renew (unsigned char *, nr_1M_px, nr_1M_size); - } - - nr_1M_px[nr_1M_len] = px; - nr_1M_len += 1; -} - -/* - 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 : diff --git a/src/libnr/nr-pixblock.h b/src/libnr/nr-pixblock.h deleted file mode 100644 index 404a0fd03..000000000 --- a/src/libnr/nr-pixblock.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef __NR_PIXBLOCK_H__ -#define __NR_PIXBLOCK_H__ - -/** \file - * \brief Pixel block structure. Used for low-level rendering. - * - * Authors: - * (C) 1999-2002 Lauris Kaplinski <lauris@kaplinski.com> - * (C) 2005 Ralf Stephan <ralf@ark.in-berlin.de> (some cleanup) - * - * This code is in the Public Domain. - */ - -#include <libnr/nr-rect-l.h> -#include <libnr/nr-forward.h> - -/// Size indicator. Hardcoded to max. 3 bits. -typedef enum { - NR_PIXBLOCK_SIZE_TINY, ///< Fits in (unsigned char *) - NR_PIXBLOCK_SIZE_4K, ///< Pixelstore - NR_PIXBLOCK_SIZE_16K, ///< Pixelstore - NR_PIXBLOCK_SIZE_64K, ///< Pixelstore - NR_PIXBLOCK_SIZE_256K, ///< Pixelstore - NR_PIXBLOCK_SIZE_1M, ///< Pixelstore - NR_PIXBLOCK_SIZE_BIG, ///< Normally allocated - NR_PIXBLOCK_SIZE_STATIC ///< Externally managed -} NR_PIXBLOCK_SIZE; - -/// Mode indicator. Hardcoded to max. 2 bits. -typedef enum { - NR_PIXBLOCK_MODE_A8, ///< Grayscale - NR_PIXBLOCK_MODE_R8G8B8, ///< 8 bit RGB - NR_PIXBLOCK_MODE_R8G8B8A8N, ///< Normal 8 bit RGBA - NR_PIXBLOCK_MODE_R8G8B8A8P ///< Premultiplied 8 bit RGBA -} NR_PIXBLOCK_MODE; - -/// The pixel block struct. -struct NRPixBlock { - NR_PIXBLOCK_SIZE size : 3; ///< Size indicator - NR_PIXBLOCK_MODE mode : 2; ///< Mode indicator - bool empty : 1; ///< Empty flag - unsigned int rs; ///< Size of line in bytes - NRRectL area; - NRRectL visible_area; - union { - unsigned char *px; ///< Pointer to buffer - unsigned char p[sizeof (unsigned char *)]; ///< Tiny buffer - } data; -}; - -/// Returns number of bytes per pixel (1, 3, or 4). -inline int -NR_PIXBLOCK_BPP (NRPixBlock *pb) -{ - return ((pb->mode == NR_PIXBLOCK_MODE_A8) ? 1 : - (pb->mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4); -} - -/// Returns pointer to pixel data. -inline unsigned char* -NR_PIXBLOCK_PX (NRPixBlock *pb) -{ - return ((pb->size == NR_PIXBLOCK_SIZE_TINY) ? - pb->data.p : pb->data.px); -} -inline unsigned char const* -NR_PIXBLOCK_PX (NRPixBlock const *pb) -{ - return ((pb->size == NR_PIXBLOCK_SIZE_TINY) ? - pb->data.p : pb->data.px); -} - -void nr_pixblock_setup (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear); -void nr_pixblock_setup_fast (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear); -void nr_pixblock_setup_extern (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, unsigned char *px, int rs, bool empty, bool clear); -void nr_pixblock_release (NRPixBlock *pb); - -NRPixBlock *nr_pixblock_new (NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear); -NRPixBlock *nr_pixblock_new_fast (NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear); -NRPixBlock *nr_pixblock_free (NRPixBlock *pb); - -unsigned char *nr_pixelstore_4K_new (bool clear, unsigned char val); -void nr_pixelstore_4K_free (unsigned char *px); -unsigned char *nr_pixelstore_16K_new (bool clear, unsigned char val); -void nr_pixelstore_16K_free (unsigned char *px); -unsigned char *nr_pixelstore_64K_new (bool clear, unsigned char val); -void nr_pixelstore_64K_free (unsigned char *px); -unsigned char *nr_pixelstore_256K_new (bool clear, unsigned char val); -void nr_pixelstore_256K_free (unsigned char *px); -unsigned char *nr_pixelstore_1M_new (bool clear, unsigned char val); -void nr_pixelstore_1M_free (unsigned char *px); - -#endif -/* - 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 : diff --git a/src/libnr/nr-pixops.h b/src/libnr/nr-pixops.h deleted file mode 100644 index 92196928a..000000000 --- a/src/libnr/nr-pixops.h +++ /dev/null @@ -1,148 +0,0 @@ -#ifndef __NR_PIXOPS_H__ -#define __NR_PIXOPS_H__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * bulia byak <buliabyak@users.sf.net> - * - * This code is in public domain - */ - -#define NR_RGBA32_R(v) (unsigned char) (((v) >> 24) & 0xff) -#define NR_RGBA32_G(v) (unsigned char) (((v) >> 16) & 0xff) -#define NR_RGBA32_B(v) (unsigned char) (((v) >> 8) & 0xff) -#define NR_RGBA32_A(v) (unsigned char) ((v) & 0xff) - -// FAST_DIVIDE assumes that 0<=num<=256*denom -// (this covers the case that num=255*denom+denom/2, which is used by DIV_ROUND) -template<unsigned int divisor> static inline unsigned int FAST_DIVIDE(unsigned int v) { return v/divisor; } -template<> inline unsigned int FAST_DIVIDE<255>(unsigned int v) { return ((v+1)*0x101) >> 16; } -template<> inline unsigned int FAST_DIVIDE<255*255>(unsigned int v) { v=(v+1)<<1; v=v+(v>>7)+((v*0x3)>>16)+(v>>22); return (v>>16)>>1; } -// FAST_DIV_ROUND assumes that 0<=num<=255*denom (DIV_ROUND should work upto num=2^32-1-(denom/2), -// but FAST_DIVIDE_BY_255 already fails at num=65790=258*255, which is not too far above 255.5*255) -template<unsigned int divisor> static inline unsigned int FAST_DIV_ROUND(unsigned int v) { return FAST_DIVIDE<divisor>(v+(divisor)/2); } -static inline unsigned int DIV_ROUND(unsigned int v, unsigned int divisor) { return (v+divisor/2)/divisor; } - -#define INK_COMPOSE(f,a,b) ( ( ((guchar) (b)) * ((guchar) (0xff - (a))) + ((guchar) (((b) ^ ~(f)) + (b)/4 - ((b)>127? 63 : 0))) * ((guchar) (a)) ) >>8) - -// Naming: OPb_i+o -// OP = operation, for example: NORMALIZE, COMPOSEA, COMPOSENNN, PREMUL, etc. -// i+o = range of input/output as powers of 2^8-1 -// for example, 213 means 0<=a<=255^2, 0<=b<=255, 0<=output<=255^3 - -// Normalize -static inline unsigned int NR_NORMALIZE_11(unsigned int v) { return v; } -static inline unsigned int NR_NORMALIZE_21(unsigned int v) { return FAST_DIV_ROUND<255>(v); } -static inline unsigned int NR_NORMALIZE_31(unsigned int v) { return FAST_DIV_ROUND<255*255>(v); } -static inline unsigned int NR_NORMALIZE_41(unsigned int v) { return FAST_DIV_ROUND<255*255*255>(v); } - -// Compose alpha channel using (1 - (1-a)*(1-b)) -// Note that these can also be rewritten to NR_COMPOSENPP(255, a, b), slightly slower, but could help if someone -// decides to use SSE or something similar (for allowing the four components to be treated the same way). -static inline unsigned int NR_COMPOSEA_213(unsigned int a, unsigned int b) { return 255*255*255 - (255*255-a)*(255-b); } -static inline unsigned int NR_COMPOSEA_112(unsigned int a, unsigned int b) { return 255*255 - (255-a)*(255-b); } -static inline unsigned int NR_COMPOSEA_211(unsigned int a, unsigned int b) { return NR_NORMALIZE_31(NR_COMPOSEA_213(a, b)); } -static inline unsigned int NR_COMPOSEA_111(unsigned int a, unsigned int b) { return NR_NORMALIZE_21(NR_COMPOSEA_112(a, b)); } - -// Operation: (1 - fa) * bc * ba + fa * fc -static inline unsigned int NR_COMPOSENNP_12114(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba) { return (255*255 - fa) * ba * bc + 255 * fa * fc; } -static inline unsigned int NR_COMPOSENNP_11113(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba) { return (255 - fa) * ba * bc + 255 * fa * fc; } -static inline unsigned int NR_COMPOSENNP_11111(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba) { return NR_NORMALIZE_31(NR_COMPOSENNP_11113(fc, fa, bc, ba)); } - -// Operation: (1 - fa) * bc * ba + fc -static inline unsigned int NR_COMPOSEPNP_32114(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba) { return (255*255 - fa) * ba * bc + 255 * fc; } -static inline unsigned int NR_COMPOSEPNP_22114(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba) { return (255*255 - fa) * ba * bc + 255*255 * fc; } -static inline unsigned int NR_COMPOSEPNP_11113(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba) { return (255 - fa) * ba * bc + 255*255 * fc; } -static inline unsigned int NR_COMPOSEPNP_22111(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba) { return NR_NORMALIZE_41(NR_COMPOSEPNP_22114(fc, fa, bc, ba)); } -static inline unsigned int NR_COMPOSEPNP_11111(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba) { return NR_NORMALIZE_31(NR_COMPOSEPNP_11113(fc, fa, bc, ba)); } - -// Operation: ((1 - fa) * bc * ba + fa * fc)/a -// Reuses non-normalized versions of NR_COMPOSENNP -static inline unsigned int NR_COMPOSENNN_121131(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba, unsigned int a) { return DIV_ROUND(NR_COMPOSENNP_12114(fc, fa, bc, ba), a); } -static inline unsigned int NR_COMPOSENNN_111121(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba, unsigned int a) { return DIV_ROUND(NR_COMPOSENNP_11113(fc, fa, bc, ba), a); } - -// Operation: ((1 - fa) * bc * ba + fc)/a -// Reuses non-normalized versions of NR_COMPOSEPNP -static inline unsigned int NR_COMPOSEPNN_321131(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba, unsigned int a) { return DIV_ROUND(NR_COMPOSEPNP_32114(fc, fa, bc, ba), a); } -static inline unsigned int NR_COMPOSEPNN_221131(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba, unsigned int a) { return DIV_ROUND(NR_COMPOSEPNP_22114(fc, fa, bc, ba), a); } -static inline unsigned int NR_COMPOSEPNN_111121(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba, unsigned int a) { return DIV_ROUND(NR_COMPOSEPNP_11113(fc, fa, bc, ba), a); } - -// Operation: (1 - fa) * bc + fa * fc -// (1-fa)*bc+fa*fc = bc-fa*bc+fa*fc = bc+fa*(fc-bc) -// For some reason it's faster to leave the initial 255*bc term in the non-normalized version instead of factoring it out... -static inline unsigned int NR_COMPOSENPP_1213(unsigned int fc, unsigned int fa, unsigned int bc) { return 255*255*bc + fa*(fc-bc); } -static inline unsigned int NR_COMPOSENPP_1123(unsigned int fc, unsigned int fa, unsigned int bc) { return 255*bc + fa*(255*fc-bc); } -static inline unsigned int NR_COMPOSENPP_1112(unsigned int fc, unsigned int fa, unsigned int bc) { return 255*bc + fa*(fc-bc); } -static inline unsigned int NR_COMPOSENPP_1211(unsigned int fc, unsigned int fa, unsigned int bc) { return NR_NORMALIZE_31(NR_COMPOSENPP_1213(fc, fa, bc)); } -static inline unsigned int NR_COMPOSENPP_1121(unsigned int fc, unsigned int fa, unsigned int bc) { return NR_NORMALIZE_31(NR_COMPOSENPP_1123(fc, fa, bc)); } -static inline unsigned int NR_COMPOSENPP_1111(unsigned int fc, unsigned int fa, unsigned int bc) { return NR_NORMALIZE_21(NR_COMPOSENPP_1112(fc, fa, bc)); } - -// Operation: (1 - fa) * bc + fc -// (1-fa)*bc+fc = bc-fa*bc+fc = (bc+fc)-fa*bc -// This rewritten form results in faster code (found out through testing) -static inline unsigned int NR_COMPOSEPPP_2224(unsigned int fc, unsigned int fa, unsigned int bc) { return 255*255*(bc+fc) - fa*bc; } // Note that this can temporarily overflow (but it probably doesn't cause problems) - // NR_COMPOSEPPP_2224 assumes that fa and fc have a common component (fa=a*x and fc=c*x), because then the maximum value is: - // (255*255-255*x)*255*255 + 255*x*255*255 = 255*255*( (255*255-255*x) + 255*x ) = 255*255*255*( (255-x)+x ) = 255*255*255*255 -static inline unsigned int NR_COMPOSEPPP_3213(unsigned int fc, unsigned int fa, unsigned int bc) { return 255*255*bc + fc - fa*bc; } -static inline unsigned int NR_COMPOSEPPP_2213(unsigned int fc, unsigned int fa, unsigned int bc) { return 255*(255*bc+fc) - fa*bc; } -static inline unsigned int NR_COMPOSEPPP_1213(unsigned int fc, unsigned int fa, unsigned int bc) { return 255*255*(bc+fc) - fa*bc; } -static inline unsigned int NR_COMPOSEPPP_1112(unsigned int fc, unsigned int fa, unsigned int bc) { return 255*(bc+fc) - fa*bc; } -static inline unsigned int NR_COMPOSEPPP_2221(unsigned int fc, unsigned int fa, unsigned int bc) { return NR_NORMALIZE_41(NR_COMPOSEPPP_2224(fc, fa, bc)); } -static inline unsigned int NR_COMPOSEPPP_3211(unsigned int fc, unsigned int fa, unsigned int bc) { return NR_NORMALIZE_31(NR_COMPOSEPPP_3213(fc, fa, bc)); } -static inline unsigned int NR_COMPOSEPPP_2211(unsigned int fc, unsigned int fa, unsigned int bc) { return NR_NORMALIZE_31(NR_COMPOSEPPP_2213(fc, fa, bc)); } -static inline unsigned int NR_COMPOSEPPP_1211(unsigned int fc, unsigned int fa, unsigned int bc) { return NR_NORMALIZE_21(NR_COMPOSEPPP_1213(fc, fa, bc)); } -static inline unsigned int NR_COMPOSEPPP_1111(unsigned int fc, unsigned int fa, unsigned int bc) { return NR_NORMALIZE_21(NR_COMPOSEPPP_1112(fc, fa, bc)); } - -#define NR_COMPOSEN11_1211 NR_COMPOSENPP_1211 -#define NR_COMPOSEN11_1111 NR_COMPOSENPP_1111 -//inline unsigned int NR_COMPOSEN11_1111(unsigned int fc, unsigned int fa, unsigned int bc) { return NR_NORMALIZE_21((255 - fa) * bc + fa * fc ); } - -#define NR_COMPOSEP11_2211 NR_COMPOSEPPP_2211 -#define NR_COMPOSEP11_1211 NR_COMPOSEPPP_1211 -#define NR_COMPOSEP11_1111 NR_COMPOSEPPP_1111 -//inline unsigned int NR_COMPOSEP11_1111(unsigned int fc, unsigned int fa, unsigned int bc) { return NR_NORMALIZE_21((255 - fa) * bc + fc * 255); } - -// Premultiply using c*a -static inline unsigned int NR_PREMUL_134(unsigned int c, unsigned int a) { return c * a; } -static inline unsigned int NR_PREMUL_224(unsigned int c, unsigned int a) { return c * a; } -static inline unsigned int NR_PREMUL_123(unsigned int c, unsigned int a) { return c * a; } -static inline unsigned int NR_PREMUL_112(unsigned int c, unsigned int a) { return c * a; } -static inline unsigned int NR_PREMUL_314(unsigned int c, unsigned int a) { return NR_PREMUL_134(c, a); } -static inline unsigned int NR_PREMUL_213(unsigned int c, unsigned int a) { return NR_PREMUL_123(c, a); } -static inline unsigned int NR_PREMUL_131(unsigned int c, unsigned int a) { return NR_NORMALIZE_41(NR_PREMUL_134(c, a)); } -static inline unsigned int NR_PREMUL_221(unsigned int c, unsigned int a) { return NR_NORMALIZE_41(NR_PREMUL_224(c, a)); } -static inline unsigned int NR_PREMUL_121(unsigned int c, unsigned int a) { return NR_NORMALIZE_31(NR_PREMUL_123(c, a)); } -static inline unsigned int NR_PREMUL_111(unsigned int c, unsigned int a) { return NR_NORMALIZE_21(NR_PREMUL_112(c, a)); } -static inline unsigned int NR_PREMUL_311(unsigned int c, unsigned int a) { return NR_NORMALIZE_41(NR_PREMUL_314(c, a)); } -static inline unsigned int NR_PREMUL_211(unsigned int c, unsigned int a) { return NR_NORMALIZE_31(NR_PREMUL_213(c, a)); } - -// Demultiply using c/a -static inline unsigned int NR_DEMUL_131(unsigned int c, unsigned int a) { return DIV_ROUND(255 * 255 * 255 * c, a); } -static inline unsigned int NR_DEMUL_231(unsigned int c, unsigned int a) { return DIV_ROUND(255 * 255 * c, a); } -static inline unsigned int NR_DEMUL_121(unsigned int c, unsigned int a) { return DIV_ROUND(255 * 255 * c, a); } -static inline unsigned int NR_DEMUL_331(unsigned int c, unsigned int a) { return DIV_ROUND(255 * c, a); } -static inline unsigned int NR_DEMUL_221(unsigned int c, unsigned int a) { return DIV_ROUND(255 * c, a); } -static inline unsigned int NR_DEMUL_111(unsigned int c, unsigned int a) { return DIV_ROUND(255 * c, a); } -static inline unsigned int NR_DEMUL_431(unsigned int c, unsigned int a) { return DIV_ROUND(c, a); } -static inline unsigned int NR_DEMUL_321(unsigned int c, unsigned int a) { return DIV_ROUND(c, a); } -static inline unsigned int NR_DEMUL_211(unsigned int c, unsigned int a) { return DIV_ROUND(c, a); } -static inline unsigned int NR_DEMUL_421(unsigned int c, unsigned int a) { return DIV_ROUND(c, 255 * a); } -static inline unsigned int NR_DEMUL_311(unsigned int c, unsigned int a) { return DIV_ROUND(c, 255 * a); } -static inline unsigned int NR_DEMUL_411(unsigned int c, unsigned int a) { return DIV_ROUND(c, 255 * 255 * a); } - - -#endif - -/* - 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 : diff --git a/src/libnr/nr-point-matrix-ops.h b/src/libnr/nr-point-matrix-ops.h deleted file mode 100644 index 7bed71587..000000000 --- a/src/libnr/nr-point-matrix-ops.h +++ /dev/null @@ -1,49 +0,0 @@ -/** @file - * @brief Operator functions over (NR::Point, NR::Matrix) - */ -#ifndef SEEN_NR_POINT_MATRIX_OPS_H -#define SEEN_NR_POINT_MATRIX_OPS_H - -#include "libnr/nr-point.h" -#include "libnr/nr-matrix.h" - -namespace NR { - -inline Point operator*(Point const &v, Matrix const &m) -{ -#if 1 /* Which code makes it easier to see what's happening? */ - NR::Point const xform_col0(m[0], - m[2]); - NR::Point const xform_col1(m[1], - m[3]); - NR::Point const xlate(m[4], m[5]); - return ( Point(dot(v, xform_col0), - dot(v, xform_col1)) - + xlate ); -#else - return Point(v[X] * m[0] + v[Y] * m[2] + m[4], - v[X] * m[1] + v[Y] * m[3] + m[5]); -#endif -} - -inline Point &Point::operator*=(Matrix const &m) -{ - *this = *this * m; - return *this; -} - -} /* namespace NR */ - - -#endif /* !SEEN_NR_POINT_MATRIX_OPS_H */ - -/* - 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 : diff --git a/src/libnr/nr-rect.cpp b/src/libnr/nr-rect.cpp index 1e1f36104..58e16e963 100644 --- a/src/libnr/nr-rect.cpp +++ b/src/libnr/nr-rect.cpp @@ -11,6 +11,7 @@ #include "nr-rect-l.h" #include <algorithm> +#include "nr-point-ops.h" NRRect::NRRect(NR::Rect const &rect) : x0(rect.min()[NR::X]), y0(rect.min()[NR::Y]), @@ -220,6 +221,8 @@ nr_rect_d_union_xy (NRRect *d, NR::Coord x, NR::Coord y) NRRect * nr_rect_d_matrix_transform(NRRect *d, NRRect const *const s, NR::Matrix const &m) { + // defunct + /* using NR::X; using NR::Y; @@ -238,7 +241,7 @@ nr_rect_d_matrix_transform(NRRect *d, NRRect const *const s, NR::Matrix const &m std::max(c10[X], c11[X])); d->y1 = std::max(std::max(c00[Y], c01[Y]), std::max(c10[Y], c11[Y])); - } + }*/ return d; } diff --git a/src/libnr/nr-rect.h b/src/libnr/nr-rect.h index ea656c8e1..aa5921309 100644 --- a/src/libnr/nr-rect.h +++ b/src/libnr/nr-rect.h @@ -16,19 +16,23 @@ #include <stdexcept> #include <limits> +#include <glib.h> #include "libnr/nr-values.h" #include <libnr/nr-coord.h> #include <libnr/nr-i-coord.h> #include <libnr/nr-dim2.h> #include <libnr/nr-point.h> +#include "libnr/nr-point-ops.h" +#include "libnr/nr-macros.h" #include <boost/optional.hpp> -#include <libnr/nr-point-matrix-ops.h> #include <libnr/nr-forward.h> #include <2geom/rect.h> namespace NR { +class Matrix; + /** A rectangle is always aligned to the X and Y axis. This means it * can be defined using only 4 coordinates, and determining * intersection is very efficient. The points inside a rectangle are @@ -136,11 +140,6 @@ public: return Rect(s * min(), s * max()); } - /** Transforms the rect by m. Note that it gives correct results only for scales and translates */ - inline Rect operator*(Matrix const m) const { - return Rect(_min * m, _max * m); - } - inline bool operator==(Rect const &in_rect) { return ((this->min() == in_rect.min()) && (this->max() == in_rect.max())); } diff --git a/src/libnr/nr-rotate-fns-test.h b/src/libnr/nr-rotate-fns-test.h deleted file mode 100644 index 9d85da097..000000000 --- a/src/libnr/nr-rotate-fns-test.h +++ /dev/null @@ -1,54 +0,0 @@ -#include <cxxtest/TestSuite.h> - -#include <cmath> -#include <glib/gmacros.h> - -#include <libnr/nr-rotate-fns.h> - -class NrRotateFnsTest : public CxxTest::TestSuite -{ -public: - - NrRotateFnsTest() - { - } - virtual ~NrRotateFnsTest() {} - -// createSuite and destroySuite get us per-suite setup and teardown -// without us having to worry about static initialization order, etc. - static NrRotateFnsTest *createSuite() { return new NrRotateFnsTest(); } - static void destroySuite( NrRotateFnsTest *suite ) { delete suite; } - - - - void testRotateDegrees(void) - { - double const d[] = { - 0, 90, 180, 270, 360, 45, 45.01, 44.99, 134, 135, 136, 314, 315, 317, 359, 361 - }; - for ( unsigned i = 0; i < G_N_ELEMENTS(d); ++i ) { - double const degrees = d[i]; - NR::rotate const rot(rotate_degrees(degrees)); - NR::rotate const rot_approx( M_PI * ( degrees / 180. ) ); - TS_ASSERT( rotate_equalp(rot, rot_approx, 1e-12) ); - - NR::rotate const rot_inv(rotate_degrees(-degrees)); - NR::rotate const rot_compl(rotate_degrees(360 - degrees)); - TS_ASSERT( rotate_equalp(rot_inv, rot_compl, 1e-12) ); - - TS_ASSERT( !rotate_equalp(rot, rotate_degrees(degrees + 1), 1e-5) ); - } - } - -}; - -/* - 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 : diff --git a/src/libnr/nr-rotate-fns.cpp b/src/libnr/nr-rotate-fns.cpp deleted file mode 100644 index f2669c20c..000000000 --- a/src/libnr/nr-rotate-fns.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/** \file - * Functions to/from NR::rotate. - */ -#include <glib.h> -#include "libnr/nr-rotate-ops.h" -#include "libnr/nr-rotate-fns.h" - -/** - * Returns a rotation matrix corresponding by the specified angle about the origin. - * - * Angle direction in Inkscape code: If you use the traditional mathematics convention that y - * increases upwards, then positive angles are anticlockwise as per the mathematics convention. If - * you take the common non-mathematical convention that y increases downwards, then positive angles - * are clockwise, as is common outside of mathematics. - */ -NR::rotate -rotate_degrees(double degrees) -{ - if (degrees < 0) { - return rotate_degrees(-degrees).inverse(); - } - - double const degrees0 = degrees; - if (degrees >= 360) { - degrees = fmod(degrees, 360); - } - - NR::rotate ret(1., 0.); - - if (degrees >= 180) { - NR::rotate const rot180(-1., 0.); - degrees -= 180; - ret = rot180; - } - - if (degrees >= 90) { - NR::rotate const rot90(0., 1.); - degrees -= 90; - ret *= rot90; - } - - if (degrees == 45) { - NR::rotate const rot45(M_SQRT1_2, M_SQRT1_2); - ret *= rot45; - } else { - double const radians = M_PI * ( degrees / 180 ); - ret *= NR::rotate(cos(radians), sin(radians)); - } - - NR::rotate const raw_ret( M_PI * ( degrees0 / 180 ) ); - g_return_val_if_fail(rotate_equalp(ret, raw_ret, 1e-8), - raw_ret); - return ret; -} - - -/* - 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 : diff --git a/src/libnr/nr-rotate-fns.h b/src/libnr/nr-rotate-fns.h deleted file mode 100644 index bd075114c..000000000 --- a/src/libnr/nr-rotate-fns.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef SEEN_NR_ROTATE_FNS_H -#define SEEN_NR_ROTATE_FNS_H - -/** \file - * Declarations for rotation functions. - */ - -#include <libnr/nr-rotate.h> -#include <libnr/nr-point-fns.h> - -inline bool rotate_equalp(NR::rotate const &a, NR::rotate const &b, double const eps) -{ - return point_equalp(a.vec, b.vec, eps); -} - -NR::rotate rotate_degrees(double degrees); - -#endif /* !SEEN_NR_ROTATE_FNS_H */ - -/* - 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 : diff --git a/src/libnr/nr-rotate-matrix-ops.cpp b/src/libnr/nr-rotate-matrix-ops.cpp deleted file mode 100644 index a2dd44b43..000000000 --- a/src/libnr/nr-rotate-matrix-ops.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include <libnr/nr-matrix-ops.h> - -NR::Matrix -operator*(NR::rotate const &a, NR::Matrix const &b) -{ - return NR::Matrix(a) * b; -} - - -/* - 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 : diff --git a/src/libnr/nr-rotate-matrix-ops.h b/src/libnr/nr-rotate-matrix-ops.h deleted file mode 100644 index e34cc623b..000000000 --- a/src/libnr/nr-rotate-matrix-ops.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef SEEN_LIBNR_NR_ROTATE_MATRIX_OPS_H -#define SEEN_LIBNR_NR_ROTATE_MATRIX_OPS_H - -#include <libnr/nr-forward.h> - - -NR::Matrix operator*(NR::rotate const &a, NR::Matrix const &b); - - -#endif /* !SEEN_LIBNR_NR_ROTATE_MATRIX_OPS_H */ - -/* - 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 : diff --git a/src/libnr/nr-rotate-ops.h b/src/libnr/nr-rotate-ops.h deleted file mode 100644 index 80eb57b9c..000000000 --- a/src/libnr/nr-rotate-ops.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef SEEN_NR_ROTATE_OPS_H -#define SEEN_NR_ROTATE_OPS_H -#include <libnr/nr-rotate.h> - -namespace NR { - -inline Point operator*(Point const &v, rotate const &r) -{ - return Point(r.vec[X] * v[X] - r.vec[Y] * v[Y], - r.vec[Y] * v[X] + r.vec[X] * v[Y]); -} - -inline rotate operator*(rotate const &a, rotate const &b) -{ - return rotate( a.vec * b ); -} - -inline rotate &rotate::operator*=(rotate const &b) -{ - *this = *this * b; - return *this; -} - -inline rotate operator/(rotate const &numer, rotate const &denom) -{ - return numer * denom.inverse(); -} - -} /* namespace NR */ - - -#endif /* !SEEN_NR_ROTATE_OPS_H */ - -/* - 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 : diff --git a/src/libnr/nr-rotate-test.h b/src/libnr/nr-rotate-test.h deleted file mode 100644 index 4b3501113..000000000 --- a/src/libnr/nr-rotate-test.h +++ /dev/null @@ -1,110 +0,0 @@ -#include <cxxtest/TestSuite.h> - -#include <cmath> -#include <libnr/nr-matrix.h> -#include <libnr/nr-matrix-ops.h> -#include <libnr/nr-matrix-fns.h> /* identity, matrix_equalp */ -#include <libnr/nr-point-fns.h> -#include <libnr/nr-rotate.h> -#include <libnr/nr-rotate-fns.h> -#include <libnr/nr-rotate-ops.h> - - -class NrRotateTest : public CxxTest::TestSuite -{ -public: - - NrRotateTest() : - m_id( NR::identity() ), - r_id( 0.0 ), - rot234( .234 ), - b( -2.0, 3.0 ), - rot180( NR::Point(-1.0, 0.0) ) - { - } - virtual ~NrRotateTest() {} - -// createSuite and destroySuite get us per-suite setup and teardown -// without us having to worry about static initialization order, etc. - static NrRotateTest *createSuite() { return new NrRotateTest(); } - static void destroySuite( NrRotateTest *suite ) { delete suite; } - - NR::Matrix const m_id; - NR::rotate const r_id; - NR::rotate const rot234; - NR::Point const b; - NR::rotate const rot180; - - - - - void testCtorsCompares(void) - { - TS_ASSERT_EQUALS( r_id, r_id ); - TS_ASSERT_EQUALS( rot234, rot234 ); - TS_ASSERT_DIFFERS( rot234, r_id ); - TS_ASSERT_EQUALS( r_id, NR::rotate(NR::Point(1.0, 0.0)) ); - TS_ASSERT_EQUALS( NR::Matrix(r_id), m_id ); - TS_ASSERT( NR::Matrix(r_id).test_identity() ); - - TS_ASSERT(rotate_equalp(rot234, NR::rotate(NR::Point(cos(.234), sin(.234))), 1e-12)); - } - - void testAssignmentOp(void) - { - NR::rotate rot234_eq(r_id); - rot234_eq = rot234; - TS_ASSERT_EQUALS( rot234, rot234_eq ); - TS_ASSERT_DIFFERS( rot234_eq, r_id ); - } - - void testInverse(void) - { - TS_ASSERT_EQUALS( r_id.inverse(), r_id ); - TS_ASSERT_EQUALS( rot234.inverse(), NR::rotate(-.234) ); - } - - void testOpStarPointRotate(void) - { - TS_ASSERT_EQUALS( b * r_id, b ); - TS_ASSERT_EQUALS( b * rot180, -b ); - TS_ASSERT_EQUALS( b * rot234, b * NR::Matrix(rot234) ); - TS_ASSERT(point_equalp(b * NR::rotate(M_PI / 2), - NR::rot90(b), - 1e-14)); - TS_ASSERT_EQUALS( b * rotate_degrees(90.), NR::rot90(b) ); - } - - void testOpStarRotateRotate(void) - { - TS_ASSERT_EQUALS( r_id * r_id, r_id ); - TS_ASSERT_EQUALS( rot180 * rot180, r_id ); - TS_ASSERT_EQUALS( rot234 * r_id, rot234 ); - TS_ASSERT_EQUALS( r_id * rot234, rot234 ); - TS_ASSERT( rotate_equalp(rot234 * rot234.inverse(), r_id, 1e-14) ); - TS_ASSERT( rotate_equalp(rot234.inverse() * rot234, r_id, 1e-14) ); - TS_ASSERT( rotate_equalp(( NR::rotate(0.25) * NR::rotate(.5) ), - NR::rotate(.75), - 1e-10) ); - } - - void testOpDivRotateRotate(void) - { - TS_ASSERT_EQUALS( rot234 / r_id, rot234 ); - TS_ASSERT_EQUALS( rot234 / rot180, rot234 * rot180 ); - TS_ASSERT( rotate_equalp(rot234 / rot234, r_id, 1e-14) ); - TS_ASSERT( rotate_equalp(r_id / rot234, rot234.inverse(), 1e-14) ); - } - -}; - -/* - 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 : diff --git a/src/libnr/nr-rotate.h b/src/libnr/nr-rotate.h deleted file mode 100644 index 6464983ab..000000000 --- a/src/libnr/nr-rotate.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef SEEN_NR_ROTATE_H -#define SEEN_NR_ROTATE_H - -/** \file - * Rotation about the origin. - */ - -#include <libnr/nr-point.h> -#include <libnr/nr-point-fns.h> -#include <libnr/nr-point-ops.h> - -namespace NR { - -/** Notionally an NR::Matrix corresponding to rotation about the origin. - Behaves like NR::Matrix for multiplication. -**/ -class rotate { -public: - Point vec; - -private: - rotate(); - -public: - explicit rotate(Coord theta); - explicit rotate(Point const &p) : vec(p) {} - explicit rotate(Coord const x, Coord const y) : vec(x, y) {} - - bool operator==(rotate const &o) const { - return vec == o.vec; - } - - bool operator!=(rotate const &o) const { - return vec != o.vec; - } - - inline rotate &operator*=(rotate const &b); - /* Defined in nr-rotate-ops.h. */ - - rotate inverse() const { - /** \todo - * In the usual case that vec is a unit vector (within rounding error), - * dividing by len_sq is either a noop or numerically harmful. - * Make a unit_rotate class (or the like) that knows its length is 1. - */ - double const len_sq = dot(vec, vec); - return rotate( Point(vec[X], -vec[Y]) - / len_sq ); - } -}; - -} /* namespace NR */ - - -#endif /* !SEEN_NR_ROTATE_H */ - -/* - 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 : diff --git a/src/libnr/nr-scale-matrix-ops.cpp b/src/libnr/nr-scale-matrix-ops.cpp deleted file mode 100644 index 4bb90196e..000000000 --- a/src/libnr/nr-scale-matrix-ops.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "libnr/nr-matrix-ops.h" - -NR::Matrix -operator*(NR::scale const &s, NR::Matrix const &m) -{ - using NR::X; using NR::Y; - NR::Matrix ret(m); - ret[0] *= s[X]; - ret[1] *= s[X]; - ret[2] *= s[Y]; - ret[3] *= s[Y]; - return ret; -} - - -/* - 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 : diff --git a/src/libnr/nr-scale-matrix-ops.h b/src/libnr/nr-scale-matrix-ops.h deleted file mode 100644 index bf1b498c9..000000000 --- a/src/libnr/nr-scale-matrix-ops.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef SEEN_LIBNR_NR_SCALE_MATRIX_OPS_H -#define SEEN_LIBNR_NR_SCALE_MATRIX_OPS_H -/** \file - * Declarations (and definition if inline) of operator - * blah (NR::scale, NR::Matrix). - */ - -#include "libnr/nr-forward.h" - -NR::Matrix operator*(NR::scale const &s, NR::Matrix const &m); - - -#endif /* !SEEN_LIBNR_NR_SCALE_MATRIX_OPS_H */ diff --git a/src/libnr/nr-scale-ops.h b/src/libnr/nr-scale-ops.h deleted file mode 100644 index 63bfe222a..000000000 --- a/src/libnr/nr-scale-ops.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef SEEN_NR_SCALE_OPS_H -#define SEEN_NR_SCALE_OPS_H - -#include <libnr/nr-scale.h> - -namespace NR { - -inline Point operator*(Point const &p, scale const &s) -{ - return Point(p[X] * s[X], - p[Y] * s[Y]); -} - -inline scale operator*(scale const &a, scale const &b) -{ - return scale(a[X] * b[X], - a[Y] * b[Y]); -} - -inline scale operator/(scale const &numer, scale const &denom) -{ - return scale(numer[X] / denom[X], - numer[Y] / denom[Y]); -} - -} /* namespace NR */ - - -#endif /* !SEEN_NR_SCALE_OPS_H */ - -/* - 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 : diff --git a/src/libnr/nr-scale-test.h b/src/libnr/nr-scale-test.h deleted file mode 100644 index 55384c637..000000000 --- a/src/libnr/nr-scale-test.h +++ /dev/null @@ -1,90 +0,0 @@ -#include <cxxtest/TestSuite.h> - -#include <libnr/nr-scale.h> -#include <libnr/nr-scale-ops.h> - -class NrScaleTest : public CxxTest::TestSuite -{ -public: - - NrScaleTest() : - sa( 1.5, 2.0 ), - b( -2.0, 3.0 ), - sb( b ) - { - } - virtual ~NrScaleTest() {} - -// createSuite and destroySuite get us per-suite setup and teardown -// without us having to worry about static initialization order, etc. - static NrScaleTest *createSuite() { return new NrScaleTest(); } - static void destroySuite( NrScaleTest *suite ) { delete suite; } - - NR::scale const sa; - NR::Point const b; - NR::scale const sb; - - - - void testXY_CtorArrayOperator(void) - { - TS_ASSERT_EQUALS( sa[NR::X], 1.5 ); - TS_ASSERT_EQUALS( sa[NR::Y], 2.0 ); - TS_ASSERT_EQUALS( sa[0u], 1.5 ); - TS_ASSERT_EQUALS( sa[1u], 2.0 ); - } - - - void testCopyCtor_AssignmentOp_NotEquals(void) - { - NR::scale const sa_copy(sa); - TS_ASSERT_EQUALS( sa, sa_copy ); - TS_ASSERT(!( sa != sa_copy )); - TS_ASSERT( sa != sb ); - } - - void testAssignmentOp(void) - { - NR::scale sa_eq(sb); - sa_eq = sa; - TS_ASSERT_EQUALS( sa, sa_eq ); - } - - void testPointCtor(void) - { - TS_ASSERT_EQUALS( sb[NR::X], b[NR::X] ); - TS_ASSERT_EQUALS( sb[NR::Y], b[NR::Y] ); - } - - void testOpStarPointScale(void) - { - NR::Point const ab( b * sa ); - TS_ASSERT_EQUALS( ab, NR::Point(-3.0, 6.0) ); - } - - void testOpStarScaleScale(void) - { - NR::scale const sab( sa * sb ); - TS_ASSERT_EQUALS( sab, NR::scale(-3.0, 6.0) ); - } - - void testOpDivScaleScale(void) - { - NR::scale const sa_b( sa / sb ); - NR::scale const exp_sa_b(-0.75, 2./3.); - TS_ASSERT_EQUALS( sa_b[0], exp_sa_b[0] ); -// TS_ASSERT_EQUALS( fabs( sa_b[1] - exp_sa_b[1] ) < 1e-10 ); - TS_ASSERT_DELTA( sa_b[1], exp_sa_b[1], 1e-10 ); - } -}; - -/* - 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 : diff --git a/src/libnr/nr-scale-translate-ops.cpp b/src/libnr/nr-scale-translate-ops.cpp deleted file mode 100644 index 579d071d8..000000000 --- a/src/libnr/nr-scale-translate-ops.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "libnr/nr-matrix-translate-ops.h" - -NR::Matrix -operator*(NR::scale const &s, NR::translate const &t) -{ - return NR::Matrix(s) * t; -} - - -/* - 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 : diff --git a/src/libnr/nr-scale-translate-ops.h b/src/libnr/nr-scale-translate-ops.h deleted file mode 100644 index 719b7b934..000000000 --- a/src/libnr/nr-scale-translate-ops.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef SEEN_LIBNR_NR_SCALE_TRANSLATE_OPS_H -#define SEEN_LIBNR_NR_SCALE_TRANSLATE_OPS_H - -#include "libnr/nr-forward.h" - -NR::Matrix operator*(NR::scale const &s, NR::translate const &t); - - -#endif /* !SEEN_LIBNR_NR_SCALE_TRANSLATE_OPS_H */ - -/* - 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 : diff --git a/src/libnr/nr-scale.h b/src/libnr/nr-scale.h deleted file mode 100644 index fd59dc210..000000000 --- a/src/libnr/nr-scale.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef SEEN_NR_SCALE_H -#define SEEN_NR_SCALE_H -#include <libnr/nr-point.h> -#include <libnr/nr-point-ops.h> - -namespace NR { - -class scale { -private: - Point _p; - -private: - scale(); - -public: - explicit scale(Point const &p) : _p(p) {} - scale(double const x, double const y) : _p(x, y) {} - explicit scale(double const s) : _p(s, s) {} - inline Coord operator[](Dim2 const d) const { return _p[d]; } - inline Coord operator[](unsigned const d) const { return _p[d]; } - inline Coord &operator[](Dim2 const d) { return _p[d]; } - inline Coord &operator[](unsigned const d) { return _p[d]; } - - bool operator==(scale const &o) const { - return _p == o._p; - } - - bool operator!=(scale const &o) const { - return _p != o._p; - } - - scale inverse() const { - return scale(1/_p[0], 1/_p[1]); - } - - NR::Point point() const { - return _p; - } -}; - -} /* namespace NR */ - - -#endif /* !SEEN_NR_SCALE_H */ - -/* - 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 : diff --git a/src/libnr/nr-translate-matrix-ops.cpp b/src/libnr/nr-translate-matrix-ops.cpp deleted file mode 100644 index 80d08afa8..000000000 --- a/src/libnr/nr-translate-matrix-ops.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "libnr/nr-matrix-ops.h" - -namespace NR { - -Matrix -operator*(translate const &t, Matrix const &m) -{ - Matrix ret(m); - ret[4] += m[0] * t[X] + m[2] * t[Y]; - ret[5] += m[1] * t[X] + m[3] * t[Y]; - return ret; -} - -} /* namespace NR */ - - -/* - 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 : diff --git a/src/libnr/nr-translate-matrix-ops.h b/src/libnr/nr-translate-matrix-ops.h deleted file mode 100644 index cb939d5cf..000000000 --- a/src/libnr/nr-translate-matrix-ops.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef SEEN_LIBNR_NR_TRANSLATE_MATRIX_OPS_H -#define SEEN_LIBNR_NR_TRANSLATE_MATRIX_OPS_H - -#include "libnr/nr-forward.h" - -namespace NR { -Matrix operator*(translate const &t, Matrix const &m); -} - - -#endif /* !SEEN_LIBNR_NR_TRANSLATE_MATRIX_OPS_H */ - -/* - 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 : diff --git a/src/libnr/nr-translate-ops.h b/src/libnr/nr-translate-ops.h deleted file mode 100644 index 2812893fb..000000000 --- a/src/libnr/nr-translate-ops.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef SEEN_NR_TRANSLATE_OPS_H -#define SEEN_NR_TRANSLATE_OPS_H - -#include <libnr/nr-translate.h> -#include <libnr/nr-point-ops.h> - -namespace NR { - -inline bool operator==(translate const &a, translate const &b) -{ - return a.offset == b.offset; -} - -inline bool operator!=(translate const &a, translate const &b) -{ - return !( a == b ); -} - -inline translate operator*(translate const &a, translate const &b) -{ - return translate( a.offset + b.offset ); -} - -inline Point operator*(Point const &v, translate const &t) -{ - return t.offset + v; -} - -} /* namespace NR */ - - -#endif /* !SEEN_NR_TRANSLATE_OPS_H */ - -/* - 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 : diff --git a/src/libnr/nr-translate-rotate-ops.cpp b/src/libnr/nr-translate-rotate-ops.cpp deleted file mode 100644 index 3dbe31211..000000000 --- a/src/libnr/nr-translate-rotate-ops.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include <libnr/nr-matrix-translate-ops.h> -#include <libnr/nr-rotate-ops.h> - -NR::Matrix -operator*(NR::translate const &a, NR::rotate const &b) -{ - return NR::Matrix(b) * NR::translate(a.offset * b); -} - - -/* - 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 : diff --git a/src/libnr/nr-translate-rotate-ops.h b/src/libnr/nr-translate-rotate-ops.h deleted file mode 100644 index 286e5caa7..000000000 --- a/src/libnr/nr-translate-rotate-ops.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef SEEN_LIBNR_NR_TRANSLATE_ROTATE_OPS_H -#define SEEN_LIBNR_NR_TRANSLATE_ROTATE_OPS_H - -#include <libnr/nr-forward.h> - - -NR::Matrix operator*(NR::translate const &a, NR::rotate const &b); - - -#endif /* !SEEN_LIBNR_NR_TRANSLATE_ROTATE_OPS_H */ - -/* - 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 : diff --git a/src/libnr/nr-translate-scale-ops.cpp b/src/libnr/nr-translate-scale-ops.cpp deleted file mode 100644 index 41e85c296..000000000 --- a/src/libnr/nr-translate-scale-ops.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "libnr/nr-matrix-ops.h" - -NR::Matrix -operator*(NR::translate const &t, NR::scale const &s) -{ - using NR::X; using NR::Y; - - NR::Matrix ret(s); - ret[4] = t[X] * s[X]; - ret[5] = t[Y] * s[Y]; - return ret; -} - - -/* - 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 : diff --git a/src/libnr/nr-translate-scale-ops.h b/src/libnr/nr-translate-scale-ops.h deleted file mode 100644 index ad362a6a7..000000000 --- a/src/libnr/nr-translate-scale-ops.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef SEEN_LIBNR_NR_TRANSLATE_SCALE_OPS_H -#define SEEN_LIBNR_NR_TRANSLATE_SCALE_OPS_H - -#include "libnr/nr-forward.h" - -NR::Matrix operator*(NR::translate const &t, NR::scale const &s); - - -#endif /* !SEEN_LIBNR_NR_TRANSLATE_SCALE_OPS_H */ - -/* - 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 : diff --git a/src/libnr/nr-translate-test.h b/src/libnr/nr-translate-test.h deleted file mode 100644 index 54d7c725f..000000000 --- a/src/libnr/nr-translate-test.h +++ /dev/null @@ -1,85 +0,0 @@ -#include <cxxtest/TestSuite.h> - -#include <libnr/nr-point-ops.h> -#include <libnr/nr-matrix.h> -#include <libnr/nr-matrix-fns.h> -#include <libnr/nr-matrix-ops.h> -#include <libnr/nr-point-matrix-ops.h> -#include <libnr/nr-translate.h> -#include <libnr/nr-translate-ops.h> - -class NrTranslateTest : public CxxTest::TestSuite -{ -public: - - NrTranslateTest() : - b( -2.0, 3.0 ), - tb( b ), - tc( -3.0, -2.0 ), - tbc( tb * tc ), - t_id( 0.0, 0.0 ), - m_id( NR::identity() ) - { - } - virtual ~NrTranslateTest() {} - -// createSuite and destroySuite get us per-suite setup and teardown -// without us having to worry about static initialization order, etc. - static NrTranslateTest *createSuite() { return new NrTranslateTest(); } - static void destroySuite( NrTranslateTest *suite ) { delete suite; } - - NR::Point const b; - NR::translate const tb; - NR::translate const tc; - NR::translate const tbc; - NR::translate const t_id; - NR::Matrix const m_id; - - - void testCtorsArrayOperator(void) - { - TS_ASSERT_EQUALS( tc[NR::X], -3.0 ); - TS_ASSERT_EQUALS( tc[NR::Y], -2.0 ); - - TS_ASSERT_EQUALS( tb[0], b[NR::X] ); - TS_ASSERT_EQUALS( tb[1], b[NR::Y] ); - } - - void testAssignmentOperator(void) - { - NR::translate tb_eq(tc); - tb_eq = tb; - TS_ASSERT_EQUALS( tb, tb_eq ); - TS_ASSERT_DIFFERS( tb_eq, tc ); - } - - void testOpStarTranslateTranslate(void) - { - TS_ASSERT_EQUALS( tbc.offset, NR::Point(-5.0, 1.0) ); - TS_ASSERT_EQUALS( tbc.offset, ( tc * tb ).offset ); - TS_ASSERT_EQUALS( NR::Matrix(tbc), NR::Matrix(tb) * NR::Matrix(tc) ); - } - - void testOpStarPointTranslate(void) - { - TS_ASSERT_EQUALS( tbc.offset, b * tc ); - TS_ASSERT_EQUALS( b * tc, b * NR::Matrix(tc) ); - } - - void testIdentity(void) - { - TS_ASSERT_EQUALS( b * t_id, b ); - TS_ASSERT_EQUALS( NR::Matrix(t_id), m_id ); - } -}; - -/* - 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 : diff --git a/src/libnr/nr-translate.h b/src/libnr/nr-translate.h deleted file mode 100644 index 65660099c..000000000 --- a/src/libnr/nr-translate.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef SEEN_NR_TRANSLATE_H -#define SEEN_NR_TRANSLATE_H - -#include <libnr/nr-point.h> - -namespace NR { - -class translate { -public: - Point offset; -private: - translate(); -public: - explicit translate(Point const &p) : offset(p) {} - explicit translate(Coord const x, Coord const y) : offset(x, y) {} - Coord operator[](Dim2 const dim) const { return offset[dim]; } - Coord operator[](unsigned const dim) const { return offset[dim]; } -}; - -} /* namespace NR */ - - -#endif /* !SEEN_NR_TRANSLATE_H */ - -/* - 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 : diff --git a/src/libnr/nr-types.h b/src/libnr/nr-types.h index 8a1cb82cd..685c29342 100644 --- a/src/libnr/nr-types.h +++ b/src/libnr/nr-types.h @@ -18,7 +18,6 @@ #include <libnr/nr-coord.h> #include <libnr/nr-dim2.h> #include <libnr/nr-i-coord.h> -#include <libnr/nr-matrix.h> #include <libnr/nr-point.h> #include <libnr/nr-point-l.h> #include <libnr/nr-point-ops.h> diff --git a/src/libnr/nr-values.cpp b/src/libnr/nr-values.cpp index f828c1396..9193eff3b 100644 --- a/src/libnr/nr-values.cpp +++ b/src/libnr/nr-values.cpp @@ -1,14 +1,12 @@ #define __NR_VALUES_C__ #include <libnr/nr-rect-l.h> -#include <libnr/nr-matrix-fns.h> - +#include "libnr/nr-rect.h" /* The following predefined objects are for reference and comparison. */ -NR::Matrix NR_MATRIX_IDENTITY = NR::identity(); NRRect NR_RECT_EMPTY(NR_HUGE, NR_HUGE, -NR_HUGE, -NR_HUGE); NRRectL NR_RECT_L_EMPTY = {NR_HUGE_L, NR_HUGE_L, -NR_HUGE_L, -NR_HUGE_L}; diff --git a/src/libnr/nr-values.h b/src/libnr/nr-values.h index 2a795e2c6..f85fca690 100644 --- a/src/libnr/nr-values.h +++ b/src/libnr/nr-values.h @@ -22,7 +22,6 @@ The following predefined objects are for reference and comparison. They are defined in nr-values.cpp */ -extern NR::Matrix NR_MATRIX_IDENTITY; extern NRRect NR_RECT_EMPTY; extern NRRectL NR_RECT_L_EMPTY; extern NRRectL NR_RECT_S_EMPTY; diff --git a/src/libnr/testnr.cpp b/src/libnr/testnr.cpp deleted file mode 100644 index 7ce01afab..000000000 --- a/src/libnr/testnr.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#define __TESTNR_C__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * This code is in public domain - */ - -#include <stdio.h> - -#if defined (_WIN32) || defined (__WIN32__) -# include <windows.h> -#include <glib.h> -#endif - - -#include "nr-blit.h" - -static double -get_time (void) -{ - GTimeVal tv; - g_get_current_time (&tv); - return tv.tv_sec + 1e-6 * tv.tv_usec; -} - -static unsigned int -rand_byte (void) -{ - return (int) (256.0 * rand () / (RAND_MAX + 1.0)); -} - -int -main (int argc, const char **argv) -{ - double start, end; - NRPixBlock d, m[16]; - int count, i; - - srand (time (NULL)); - - printf ("Initializing buffers\n"); - - /* Destination */ - nr_pixblock_setup_fast (&d, NR_PIXBLOCK_MODE_R8G8B8A8P, 0, 0, 64, 64, 1); - d.empty = 0; - - /* Masks */ - for (i = 0; i < 16; i++) { - int r, b, c; - nr_pixblock_setup_fast (&m[i], NR_PIXBLOCK_MODE_A8, 0, 0, 64, 64, 0); - for (r = 0; r < 64; r++) { - unsigned int q; - unsigned char *p; - p = NR_PIXBLOCK_PX (&m[i]) + r * m[i].rs; - for (b = 0; b < 8; b++) { - q = rand_byte (); - if (q < 120) { - for (c = 0; c < 8; c++) *p++ = 0; - } else if (q < 240) { - for (c = 0; c < 8; c++) *p++ = 255; - } else { - for (c = 0; c < 8; c++) *p++ = rand_byte (); - } - } - } - m[i].empty = 0; - } - - printf ("Random transparency\n"); - count = 0; - start = end = get_time (); - while ((end - start) < 5.0) { - unsigned char r, g, b, a; - r = rand_byte (); - g = rand_byte (); - b = rand_byte (); - a = rand_byte (); - - for (i = 0; i < 16; i++) { - nr_blit_pixblock_mask_rgba32 (&d, &m[i], (a << 24) | (g << 16) | (b << 8) | a); - count += 1; - } - end = get_time (); - } - printf ("Did %d [64x64] random buffers in %f sec\n", count, end - start); // localizing ok - printf ("%f buffers per second\n", count / (end - start)); // localizing ok - printf ("%f pixels per second\n", count * (64 * 64) / (end - start)); // localizing ok - - return 0; -} diff --git a/src/libnrtype/FontInstance.cpp b/src/libnrtype/FontInstance.cpp index 6ba6440de..1b65dd88c 100644 --- a/src/libnrtype/FontInstance.cpp +++ b/src/libnrtype/FontInstance.cpp @@ -21,10 +21,10 @@ #include FT_TRUETYPE_TABLES_H #include <pango/pangoft2.h> #include <2geom/pathvector.h> +#include <2geom/svg-path.h> #include "libnr/nr-rect.h" #include "libnrtype/font-glyph.h" #include "libnrtype/font-instance.h" -#include "libnrtype/RasterFont.h" #include "livarot/Path.h" #include "util/unordered-containers.h" @@ -44,8 +44,6 @@ struct font_style_equal : public std::binary_function<font_style, font_style, bo bool operator()(font_style const &a, font_style const &b) const; }; -typedef INK_UNORDERED_MAP<font_style, raster_font*, font_style_hash, font_style_equal> StyleMap; - static const double STROKE_WIDTH_THREASHOLD = 0.01; @@ -105,11 +103,17 @@ bool font_style_equal::operator()(const font_style &a,const font_style &b) const /* * Outline extraction */ -typedef struct ft2_to_liv { - Path* theP; - double scale; - Geom::Point last; -} ft2_to_liv; + +struct FT2GeomData { + FT2GeomData(Geom::PathBuilder &b, double s) + : builder(b) + , last(0, 0) + , scale(s) + {} + Geom::PathBuilder &builder; + Geom::Point last; + double scale; +}; // Note: Freetype 2.2.1 redefined function signatures for functions to be placed in an // FT_Outline_Funcs structure. This is needed to keep backwards compatibility with the @@ -124,46 +128,46 @@ typedef FT_Vector FREETYPE_VECTOR; // outline as returned by freetype -> livarot Path // see nr-type-ft2.cpp for the freetype -> artBPath on which this code is based -static int ft2_move_to(FREETYPE_VECTOR *to, void * i_user) { - ft2_to_liv* user=(ft2_to_liv*)i_user; - Geom::Point p(user->scale*to->x,user->scale*to->y); +static int ft2_move_to(FREETYPE_VECTOR *to, void * i_user) +{ + FT2GeomData *user = (FT2GeomData*)i_user; + Geom::Point p(to->x, to->y); // printf("m t=%f %f\n",p[0],p[1]); - user->theP->MoveTo(p); - user->last=p; + user->builder.moveTo(p * user->scale); + user->last = p; return 0; } static int ft2_line_to(FREETYPE_VECTOR *to, void *i_user) { - ft2_to_liv* user=(ft2_to_liv*)i_user; - Geom::Point p(user->scale*to->x,user->scale*to->y); + FT2GeomData *user = (FT2GeomData*)i_user; + Geom::Point p(to->x, to->y); // printf("l t=%f %f\n",p[0],p[1]); - user->theP->LineTo(p); - user->last=p; + user->builder.lineTo(p * user->scale); + user->last = p; return 0; } static int ft2_conic_to(FREETYPE_VECTOR *control, FREETYPE_VECTOR *to, void *i_user) { - ft2_to_liv* user=(ft2_to_liv*)i_user; - Geom::Point p(user->scale*to->x,user->scale*to->y),c(user->scale*control->x,user->scale*control->y); + FT2GeomData *user = (FT2GeomData*)i_user; + Geom::Point p(to->x, to->y), c(control->x, control->y); + user->builder.quadTo(c * user->scale, p * user->scale); // printf("b c=%f %f t=%f %f\n",c[0],c[1],p[0],p[1]); - user->theP->BezierTo(p); - user->theP->IntermBezierTo(c); - user->theP->EndBezierTo(); - user->last=p; + user->last = p; return 0; } static int ft2_cubic_to(FREETYPE_VECTOR *control1, FREETYPE_VECTOR *control2, FREETYPE_VECTOR *to, void *i_user) { - ft2_to_liv* user=(ft2_to_liv*)i_user; - Geom::Point p(user->scale*to->x,user->scale*to->y); - Geom::Point c1(user->scale*control1->x,user->scale*control1->y); - Geom::Point c2(user->scale*control2->x,user->scale*control2->y); + FT2GeomData *user = (FT2GeomData*)i_user; + Geom::Point p(to->x, to->y); + Geom::Point c1(control1->x, control1->y); + Geom::Point c2(control2->x, control2->y); // printf("c c1=%f %f c2=%f %f t=%f %f\n",c1[0],c1[1],c2[0],c2[1],p[0],p[1]); - user->theP->CubicTo(p,3*(c1-user->last),3*(p-c2)); - user->last=p; + //user->theP->CubicTo(p,3*(c1-user->last),3*(p-c2)); + user->builder.curveTo(c1 * user->scale, c2 * user->scale, p * user->scale); + user->last = p; return 0; } #endif @@ -182,7 +186,6 @@ font_instance::font_instance(void) : nbGlyph(0), maxGlyph(0), glyphs(0), - loadedPtr(new StyleMap()), theFace(0) { //printf("font instance born\n"); @@ -190,12 +193,6 @@ font_instance::font_instance(void) : font_instance::~font_instance(void) { - if ( loadedPtr ) { - StyleMap* tmp = static_cast<StyleMap*>(loadedPtr); - delete tmp; - loadedPtr = 0; - } - if ( daddy ) { daddy->UnrefFace(this); daddy = 0; @@ -216,9 +213,6 @@ font_instance::~font_instance(void) theFace = 0; for (int i=0;i<nbGlyph;i++) { - if ( glyphs[i].outline ) { - delete glyphs[i].outline; - } if ( glyphs[i].pathvector ) { delete glyphs[i].pathvector; } @@ -500,14 +494,19 @@ void font_instance::LoadGlyph(int glyph_id) #endif if ( id_to_no.find(glyph_id) == id_to_no.end() ) { + Geom::PathBuilder path_builder; + if ( nbGlyph >= maxGlyph ) { maxGlyph=2*nbGlyph+1; glyphs=(font_glyph*)realloc(glyphs,maxGlyph*sizeof(font_glyph)); } font_glyph n_g; - n_g.outline=NULL; n_g.pathvector=NULL; n_g.bbox[0]=n_g.bbox[1]=n_g.bbox[2]=n_g.bbox[3]=0; + n_g.h_advance = 0; + n_g.v_advance = 0; + n_g.h_width = 0; + n_g.v_width = 0; bool doAdd=false; #ifdef USE_PANGO_WIN32 @@ -526,7 +525,6 @@ void font_instance::LoadGlyph(int glyph_id) n_g.v_advance=otm.otmTextMetrics.tmHeight*scale; n_g.h_width=metrics.gmBlackBoxX*scale; n_g.v_width=metrics.gmBlackBoxY*scale; - n_g.outline=NULL; if ( bufferSize == GDI_ERROR) { // shit happened } else if ( bufferSize == 0) { @@ -538,14 +536,13 @@ void font_instance::LoadGlyph(int glyph_id) // shit happened } else { // Platform SDK is rubbish, read KB87115 instead - n_g.outline=new Path; DWORD polyOffset=0; while ( polyOffset < bufferSize ) { TTPOLYGONHEADER const *polyHeader=(TTPOLYGONHEADER const *)(buffer+polyOffset); if (polyOffset+polyHeader->cb > bufferSize) break; if (polyHeader->dwType == TT_POLYGON_TYPE) { - n_g.outline->MoveTo(pointfx_to_nrpoint(polyHeader->pfxStart, scale)); + path_builder.moveTo(pointfx_to_nrpoint(polyHeader->pfxStart, scale)); DWORD curveOffset=polyOffset+sizeof(TTPOLYGONHEADER); while ( curveOffset < polyOffset+polyHeader->cb ) { @@ -554,41 +551,40 @@ void font_instance::LoadGlyph(int glyph_id) POINTFX const *endp=p+polyCurve->cpfx; switch (polyCurve->wType) { - case TT_PRIM_LINE: - while ( p != endp ) - n_g.outline->LineTo(pointfx_to_nrpoint(*p++, scale)); - break; + case TT_PRIM_LINE: + while ( p != endp ) + path_builder.lineTo(pointfx_to_nrpoint(*p++, scale)); + break; - case TT_PRIM_QSPLINE: + case TT_PRIM_QSPLINE: { g_assert(polyCurve->cpfx >= 2); - endp -= 2; - Geom::Point this_mid=pointfx_to_nrpoint(p[0], scale); - while ( p != endp ) { - Geom::Point next_mid=pointfx_to_nrpoint(p[1], scale); - n_g.outline->BezierTo((next_mid+this_mid)/2); - n_g.outline->IntermBezierTo(this_mid); - n_g.outline->EndBezierTo(); - ++p; - this_mid=next_mid; - } - n_g.outline->BezierTo(pointfx_to_nrpoint(p[1], scale)); - n_g.outline->IntermBezierTo(this_mid); - n_g.outline->EndBezierTo(); - break; - } - case 3: // TT_PRIM_CSPLINE - g_assert(polyCurve->cpfx % 3 == 0); - while ( p != endp ) { - n_g.outline->CubicTo(pointfx_to_nrpoint(p[2], scale), pointfx_to_nrpoint(p[0], scale), pointfx_to_nrpoint(p[1], scale)); - p += 3; + // The list of points specifies one or more control points and ends with the end point. + // The intermediate points (on the curve) are the points between the control points. + Geom::Point this_control = pointfx_to_nrpoint(*p++, scale); + while ( p+1 != endp ) { // Process all "midpoints" (all points except the last) + Geom::Point new_control = pointfx_to_nrpoint(*p++, scale); + path_builder.quadTo(this_control, (new_control+this_control)/2); + this_control = new_control; } - break; + Geom::Point end = pointfx_to_nrpoint(*p++, scale); + path_builder.quadTo(this_control, end); + } + break; + + case 3: // TT_PRIM_CSPLINE + g_assert(polyCurve->cpfx % 3 == 0); + while ( p != endp ) { + path_builder.curveTo(pointfx_to_nrpoint(p[0], scale), + pointfx_to_nrpoint(p[1], scale), + pointfx_to_nrpoint(p[2], scale)); + p += 3; + } + break; } curveOffset += sizeof(TTPOLYCURVE)+sizeof(POINTFX)*(polyCurve->cpfx-1); } - n_g.outline->Close(); } polyOffset += polyHeader->cb; } @@ -620,21 +616,29 @@ void font_instance::LoadGlyph(int glyph_id) ft2_cubic_to, 0, 0 }; - n_g.outline=new Path; - ft2_to_liv tData; - tData.theP=n_g.outline; - tData.scale=1.0/((double)theFace->units_per_EM); - tData.last=Geom::Point(0,0); - FT_Outline_Decompose (&theFace->glyph->outline, &ft2_outline_funcs, &tData); + FT2GeomData user(path_builder, 1.0/((double)theFace->units_per_EM)); + FT_Outline_Decompose (&theFace->glyph->outline, &ft2_outline_funcs, &user); } doAdd=true; } #endif + path_builder.finish(); if ( doAdd ) { - if ( n_g.outline ) { - n_g.outline->FastBBox(n_g.bbox[0],n_g.bbox[1],n_g.bbox[2],n_g.bbox[3]); - n_g.pathvector=n_g.outline->MakePathVector(); + Geom::PathVector pv = path_builder.peek(); + // close all paths + for (Geom::PathVector::iterator i = pv.begin(); i != pv.end(); ++i) { + i->close(); + } + if ( !pv.empty() ) { + n_g.pathvector = new Geom::PathVector(pv); + Geom::OptRect bounds = bounds_exact(*n_g.pathvector); + if (bounds) { + n_g.bbox[0] = bounds->left(); + n_g.bbox[1] = bounds->top(); + n_g.bbox[2] = bounds->right(); + n_g.bbox[3] = bounds->bottom(); + } } glyphs[nbGlyph]=n_g; id_to_no[glyph_id]=nbGlyph; @@ -730,29 +734,6 @@ Geom::OptRect font_instance::BBox(int glyph_id) } } -Path* font_instance::Outline(int glyph_id,Path* copyInto) -{ - int no = -1; - if ( id_to_no.find(glyph_id) == id_to_no.end() ) { - LoadGlyph(glyph_id); - if ( id_to_no.find(glyph_id) == id_to_no.end() ) { - // didn't load - } else { - no = id_to_no[glyph_id]; - } - } else { - no = id_to_no[glyph_id]; - } - if ( no < 0 ) return NULL; - Path *src_o = glyphs[no].outline; - if ( copyInto ) { - copyInto->Reset(); - copyInto->Copy(src_o); - return copyInto; - } - return src_o; -} - Geom::PathVector* font_instance::PathVector(int glyph_id) { int no = -1; @@ -793,72 +774,6 @@ double font_instance::Advance(int glyph_id,bool vertical) return 0; } - -raster_font* font_instance::RasterFont(const Geom::Affine &trs, double stroke_width, bool vertical, JoinType stroke_join, ButtType stroke_cap, float /*miter_limit*/) -{ - font_style nStyle; - nStyle.transform=trs; - nStyle.vertical=vertical; - nStyle.stroke_width=stroke_width; - nStyle.stroke_cap=stroke_cap; - nStyle.stroke_join=stroke_join; - nStyle.nbDash=0; - nStyle.dash_offset=0; - nStyle.dashes=NULL; - return RasterFont(nStyle); -} - -raster_font* font_instance::RasterFont(const font_style &inStyle) -{ - raster_font *res=NULL; - double *savDashes=NULL; - font_style nStyle=inStyle; - // for some evil reason font_style doesn't have a copy ctor, so the - // stuff that should be done there is done here instead (because the - // raster_font ctor copies nStyle). - if ( (nStyle.stroke_width > 0) && (nStyle.nbDash > 0) && nStyle.dashes ) { - savDashes=nStyle.dashes; - nStyle.dashes=(double*)malloc(nStyle.nbDash*sizeof(double)); - memcpy(nStyle.dashes,savDashes,nStyle.nbDash*sizeof(double)); - } - StyleMap& loadedStyles = *static_cast<StyleMap*>(loadedPtr); - if ( loadedStyles.find(nStyle) == loadedStyles.end() ) { - raster_font *nR = new raster_font(nStyle); - nR->Ref(); - nR->daddy=this; - loadedStyles[nStyle]=nR; - res=nR; - if ( res ) { - Ref(); - } - } else { - res=loadedStyles[nStyle]; - res->Ref(); - if ( nStyle.dashes ) { - free(nStyle.dashes); // since they're not taken by a new rasterfont - } - } - nStyle.dashes=savDashes; - return res; -} - -void font_instance::RemoveRasterFont(raster_font* who) -{ - if ( who ) { - StyleMap& loadedStyles = *static_cast<StyleMap*>(loadedPtr); - if ( loadedStyles.find(who->style) == loadedStyles.end() ) { - //g_print("RemoveRasterFont failed \n"); - // not found - } else { - loadedStyles.erase(loadedStyles.find(who->style)); - //g_print("RemoveRasterFont\n"); - Unref(); - } - } -} - - - /* Local Variables: mode:c++ diff --git a/src/libnrtype/Layout-TNG-Output.cpp b/src/libnrtype/Layout-TNG-Output.cpp index 0d4d19a42..610f92582 100644 --- a/src/libnrtype/Layout-TNG-Output.cpp +++ b/src/libnrtype/Layout-TNG-Output.cpp @@ -15,9 +15,6 @@ #include "print.h" #include "extension/print.h" #include "livarot/Path.h" -#include "libnr/nr-matrix-fns.h" -#include "libnr/nr-scale-matrix-ops.h" -#include "libnr/nr-convert2geom.h" #include "font-instance.h" #include "svg/svg-length.h" #include "extension/internal/cairo-render-context.h" @@ -288,7 +285,7 @@ void Layout::showGlyphs(CairoRenderContext *ctx) const } } while (glyph_index < _glyphs.size() && _path_fitted == NULL - && NR::transform_equalp(font_matrix, glyph_matrix, NR_EPSILON) + && (font_matrix * glyph_matrix.inverse()).isIdentity() && _characters[_glyphs[glyph_index].in_character].in_span == this_span_index); // remove vertical flip diff --git a/src/libnrtype/Layout-TNG.h b/src/libnrtype/Layout-TNG.h index 5ed922969..7d0c58c3e 100644 --- a/src/libnrtype/Layout-TNG.h +++ b/src/libnrtype/Layout-TNG.h @@ -14,8 +14,6 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif -#include <libnr/nr-matrix-ops.h> -#include <libnr/nr-rotate-ops.h> #include <libnr/nr-rect.h> #include <2geom/d2.h> #include <2geom/affine.h> diff --git a/src/libnrtype/Makefile_insert b/src/libnrtype/Makefile_insert index 8f45dc94d..7cd99e1a8 100644 --- a/src/libnrtype/Makefile_insert +++ b/src/libnrtype/Makefile_insert @@ -20,10 +20,6 @@ ink_common_sources += \ libnrtype/one-box.h \ libnrtype/one-glyph.h \ libnrtype/one-para.h \ - libnrtype/RasterFont.cpp \ - libnrtype/RasterFont.h \ - libnrtype/raster-glyph.h \ - libnrtype/raster-position.h \ libnrtype/text-boundary.h \ libnrtype/TextWrapper.cpp \ libnrtype/TextWrapper.h \ diff --git a/src/libnrtype/RasterFont.cpp b/src/libnrtype/RasterFont.cpp deleted file mode 100644 index 14f6c7afa..000000000 --- a/src/libnrtype/RasterFont.cpp +++ /dev/null @@ -1,435 +0,0 @@ -/* - * RasterFont.cpp - * testICU - * - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif -#include "RasterFont.h" - -#include <livarot/float-line.h> -#include <livarot/int-line.h> -#include <livarot/Path.h> -#include <livarot/Shape.h> -#include <libnr/nr-pixblock.h> -#include <libnrtype/font-instance.h> -#include <libnrtype/raster-glyph.h> -#include <libnrtype/raster-position.h> - - -static void glyph_run_A8_OR (raster_info &dest,void */*data*/,int st,float vst,int en,float ven); - -void font_style::Apply(Path* src,Shape* dest) { - src->Convert(1); - if ( stroke_width > 0 ) { - if ( nbDash > 0 ) { - double dlen = 0.0; - const float scale = 1/*Geom::expansion(transform)*/; - for (int i = 0; i < nbDash; i++) dlen += dashes[i] * scale; - if (dlen >= 0.01) { - float sc_offset = dash_offset * scale; - float *tdashs=(float*)malloc((nbDash+1)*sizeof(float)); - while ( sc_offset >= dlen ) sc_offset-=dlen; - tdashs[0]=dashes[0] * scale; - for (int i=1;i<nbDash;i++) tdashs[i] = tdashs[i - 1] + dashes[i] * scale; - src->DashPolyline(0.0,0.0,dlen,nbDash,tdashs,true,sc_offset); - free(tdashs); - } - } - src->Stroke(dest, false, 0.5*stroke_width, stroke_join, stroke_cap, 0.5*stroke_width*stroke_miter_limit); - } else { - src->Fill(dest,0); - } -} - -raster_font::raster_font(font_style const &fstyle) : - daddy(NULL), - refCount(0), - style(fstyle), - glyph_id_to_raster_glyph_no(), - nbBase(0), - maxBase(0), - bases(NULL) -{ - // printf("raster font born\n"); -} - -raster_font::~raster_font(void) -{ -// printf("raster font death\n"); - if ( daddy ) daddy->RemoveRasterFont(this); - daddy=NULL; - if ( style.dashes ) free(style.dashes); - style.dashes=NULL; - for (int i=0;i<nbBase;i++) delete bases[i]; - if ( bases ) free(bases); -} - -void raster_font::Unref(void) -{ - refCount--; -// printf("raster %x unref'd %i\n",this,refCount); - if ( refCount <= 0 ) { - if ( daddy ) daddy->RemoveRasterFont(this); - daddy=NULL; - delete this; - } -} -void raster_font::Ref(void) -{ - refCount++; -// printf("raster %x ref'd %i\n",this,refCount); -} -raster_glyph* raster_font::GetGlyph(int glyph_id) -{ - raster_glyph *res=NULL; - if ( glyph_id_to_raster_glyph_no.find(glyph_id) == glyph_id_to_raster_glyph_no.end() ) { - LoadRasterGlyph(glyph_id); - if ( glyph_id_to_raster_glyph_no.find(glyph_id) == glyph_id_to_raster_glyph_no.end() ) { // recheck - } else { - res=bases[glyph_id_to_raster_glyph_no[glyph_id]]; - } - } else { - res=bases[glyph_id_to_raster_glyph_no[glyph_id]]; - } - return res; -} -Geom::Point raster_font::Advance(int glyph_id) -{ - if ( daddy == NULL ) return Geom::Point(0,0); - double a=daddy->Advance(glyph_id,style.vertical); - Geom::Point f_a=(style.vertical)?Geom::Point(0,a):Geom::Point(a,0); - return f_a*style.transform; -} -void raster_font::BBox(int glyph_id,NRRect *area) -{ - area->x0=area->y0=area->x1=area->y1=0; - if ( daddy == NULL ) return; - Geom::OptRect res=daddy->BBox(glyph_id); - if (res) { - Geom::Point bmi=res->min(),bma=res->max(); - Geom::Point tlp(bmi[0],bmi[1]),trp(bma[0],bmi[1]),blp(bmi[0],bma[1]),brp(bma[0],bma[1]); - tlp=tlp*style.transform; - trp=trp*style.transform; - blp=blp*style.transform; - brp=brp*style.transform; - *res=Geom::Rect(tlp,trp); - res->expandTo(blp); - res->expandTo(brp); - area->x0=(res->min())[0]; - area->y0=(res->min())[1]; - area->x1=(res->max())[0]; - area->y1=(res->max())[1]; - } else { - nr_rect_d_set_empty(area); - } -} - -void raster_font::LoadRasterGlyph(int glyph_id) -{ - raster_glyph *res=NULL; - if ( glyph_id_to_raster_glyph_no.find(glyph_id) == glyph_id_to_raster_glyph_no.end() ) { - res=new raster_glyph(); - res->daddy=this; - res->glyph_id=glyph_id; - if ( nbBase >= maxBase ) { - maxBase=2*nbBase+1; - bases=(raster_glyph**)realloc(bases,maxBase*sizeof(raster_glyph*)); - } - bases[nbBase]=res; - glyph_id_to_raster_glyph_no[glyph_id]=nbBase; - nbBase++; - } else { - res=bases[glyph_id_to_raster_glyph_no[glyph_id]]; - } - if ( res == NULL ) return; - if ( res->polygon ) return; - if ( res->outline == NULL ) { - if ( daddy == NULL ) return; - Path* outline=daddy->Outline(glyph_id,NULL); - res->outline=new Path; - if ( outline ) { - res->outline->Copy(outline); - } - res->outline->Transform(style.transform); - } - Shape* temp=new Shape; - res->polygon=new Shape; - style.Apply(res->outline,temp); - if ( style.stroke_width > 0 ) { - res->polygon->ConvertToShape(temp,fill_nonZero); - } else { - res->polygon->ConvertToShape(temp,fill_oddEven); - } - delete temp; - - res->SetSubPixelPositionning(4); -} -void raster_font::RemoveRasterGlyph(raster_glyph* who) -{ - if ( who == NULL ) return; - int glyph_id=who->glyph_id; - if ( glyph_id_to_raster_glyph_no.find(glyph_id) == glyph_id_to_raster_glyph_no.end() ) { - int no=glyph_id_to_raster_glyph_no[glyph_id]; - if ( no >= nbBase-1 ) { - } else { - bases[no]=bases[--nbBase]; - glyph_id_to_raster_glyph_no[bases[no]->glyph_id]=no; - } - glyph_id_to_raster_glyph_no.erase(glyph_id_to_raster_glyph_no.find(glyph_id)); - } else { - // not here - } -} - -/*int top,bottom; // baseline is y=0 - int* run_on_line; // array of size (bottom-top+1): run_on_line[i] gives the number of runs on line top+i - int nbRun; - float_ligne_run* runs;*/ - -raster_position::raster_position(void) -{ - top=0; - bottom=-1; - run_on_line=NULL; - nbRun=0; - runs=NULL; -} -raster_position::~raster_position(void) -{ - if ( run_on_line ) free(run_on_line); - if ( runs ) free(runs); -} - -void raster_position::AppendRuns(std::vector<float_ligne_run> const &r,int y) -{ - if ( top > bottom ) { - top=bottom=y; - if ( run_on_line ) free(run_on_line); - run_on_line=(int*)malloc(sizeof(int)); - run_on_line[0]=0; - } else { - if ( y < top ) { - // printf("wtf?\n"); - return; - } else if ( y > bottom ) { - int ob=bottom; - bottom=y; - run_on_line=(int*)realloc(run_on_line,(bottom-top+1)*sizeof(int)); - for (int i=ob+1;i<=bottom;i++) run_on_line[i-top]=0; - } - } - - if ( r.empty() == false) { - run_on_line[y - top] = r.size(); - runs = (float_ligne_run *) realloc(runs, (nbRun + r.size()) * sizeof(float_ligne_run)); - - for (int i = 0; i < int(r.size()); i++) { - runs[nbRun + i] = r[i]; - } - - nbRun += r.size(); - } -} -void raster_position::Blit(float ph,int pv,NRPixBlock &over) -{ - int base_y=top+pv; - int first_y=top+pv,last_y=bottom+pv; - if ( first_y < over.area.y0 ) first_y=over.area.y0; - if ( last_y >= over.area.y1 ) last_y=over.area.y1-1; - if ( first_y > last_y ) return; - IntLigne *theIL=new IntLigne(); - FloatLigne *theI=new FloatLigne(); - - char* mdata=(char*)over.data.px; - if ( over.size == NR_PIXBLOCK_SIZE_TINY ) mdata=(char*)over.data.p; - - for (int y=first_y;y<=last_y;y++) { - int first_r=0,last_r=0; - for (int i=base_y;i<y;i++) first_r+=run_on_line[i-base_y]; - last_r=first_r+run_on_line[y-base_y]-1; - if ( first_r <= last_r ) { - theI->Reset(); - for (int i=first_r;i<=last_r;i++) theI->AddRun(runs[i].st+ph,runs[i].en+ph,runs[i].vst,runs[i].ven,runs[i].pente); -// for (int i=first_r;i<=last_r;i++) {runs[i].st+=ph;runs[i].en+=ph;} -// theI->nbRun=theI->maxRun=last_r-first_r+1; -// theI->runs=runs+first_r; - - theIL->Copy(theI); - raster_info dest; - dest.startPix=over.area.x0; - dest.endPix=over.area.x1; - dest.sth=over.area.x0; - dest.stv=y; - dest.buffer=((uint32_t*)(mdata+(over.rs*(y-over.area.y0)))); - theIL->Raster(dest,NULL,glyph_run_A8_OR); - -// theI->nbRun=theI->maxRun=0; -// theI->runs=NULL; -// for (int i=first_r;i<=last_r;i++) {runs[i].st-=ph;runs[i].en-=ph;} - } - } - delete theIL; - delete theI; -} - - -/* raster_font* daddy; - int glyph_id; - - Path* outline; - Shape* polygon; - - int nb_sub_pixel; - raster_position* sub_pixel;*/ - -raster_glyph::raster_glyph(void) -{ - daddy=NULL; - glyph_id=0; - outline=NULL; - polygon=NULL; - nb_sub_pixel=0; - sub_pixel=NULL; -} -raster_glyph::~raster_glyph(void) -{ - if ( outline ) delete outline; - if ( polygon ) delete polygon; - if ( sub_pixel ) delete [] sub_pixel; -} - - -void raster_glyph::SetSubPixelPositionning(int nb_pos) -{ - nb_sub_pixel=nb_pos; - if ( nb_sub_pixel <= 0 ) nb_sub_pixel=0; - if ( sub_pixel ) delete [] sub_pixel; - sub_pixel=NULL; - if ( nb_sub_pixel > 0 ) { - sub_pixel=new raster_position[nb_pos]; - if ( polygon ) { - for (int i=0;i<nb_sub_pixel;i++) LoadSubPixelPosition(i); - } - } -} -void raster_glyph::LoadSubPixelPosition(int no) -{ - if ( no < 0 || no >= nb_sub_pixel ) return; - if ( sub_pixel[no].top <= sub_pixel[no].bottom ) return; - if ( polygon == NULL ) { - if ( daddy == NULL ) return; - daddy->LoadRasterGlyph(glyph_id); - if ( polygon == NULL ) return; - } - - float sub_delta=((float)no)/((float)nb_sub_pixel); - - polygon->CalcBBox(); - - float l=polygon->leftX,r=polygon->rightX,t=polygon->topY,b=polygon->bottomY; - int il,ir,it,ib; - il=(int)floor(l); - ir=(int)ceil(r); - it=(int)floor(t); - ib=(int)ceil(b); - - // version par FloatLigne - int curPt; - float curY; - polygon->BeginQuickRaster(curY, curPt); - - FloatLigne* theI=new FloatLigne(); - - polygon->DirectQuickScan(curY,curPt,(float)(it-1)+sub_delta,true,1.0); - - for (int y=it-1;y<ib;y++) { - theI->Reset(); - polygon->QuickScan(curY,curPt,((float)(y+1))+sub_delta,theI,1.0); - theI->Flatten(); - - sub_pixel[no].AppendRuns(theI->runs, y); - } - polygon->EndQuickRaster(); - delete theI; -} - -void raster_glyph::Blit(const Geom::Point &at,NRPixBlock &over) -{ - if ( nb_sub_pixel <= 0 ) return; - int pv=(int)ceil(at[1]); - double dec=4*(ceil(at[1])-at[1]); - int no=(int)floor(dec); - sub_pixel[no].Blit(at[0],pv,over); -} - - - -static void -glyph_run_A8_OR (raster_info &dest,void */*data*/,int st,float vst,int en,float ven) -{ - if ( st >= en ) return; - if ( vst < 0 ) vst=0; - if ( vst > 1 ) vst=1; - if ( ven < 0 ) ven=0; - if ( ven > 1 ) ven=1; - float sv=vst; - float dv=ven-vst; - int len=en-st; - unsigned char* d=(unsigned char*)dest.buffer; - d+=(st-dest.startPix); - if ( fabs(dv) < 0.001 ) { - if ( vst > 0.999 ) { - /* Simple copy */ - while (len > 0) { - d[0] = 255; - d += 1; - len -= 1; - } - } else { - sv*=256; - unsigned int c0_24=(int)sv; - c0_24&=0xFF; - while (len > 0) { - unsigned int da; - /* Draw */ - da = 65025 - (255 - c0_24) * (255 - d[0]); - d[0] = (da + 127) / 255; - d += 1; - len -= 1; - } - } - } else { - if ( en <= st+1 ) { - sv=0.5*(vst+ven); - sv*=256; - unsigned int c0_24=(int)sv; - c0_24&=0xFF; - unsigned int da; - /* Draw */ - da = 65025 - (255 - c0_24) * (255 - d[0]); - d[0] = (da + 127) / 255; - } else { - dv/=len; - sv+=0.5*dv; // correction trapezoidale - sv*=16777216; - dv*=16777216; - int c0_24 = static_cast<int>(CLAMP(sv, 0, 16777216)); - int s0_24 = static_cast<int>(dv); - while (len > 0) { - unsigned int ca, da; - /* Draw */ - ca = c0_24 >> 16; - if ( ca > 255 ) ca=255; - da = 65025 - (255 - ca) * (255 - d[0]); - d[0] = (da + 127) / 255; - d += 1; - c0_24 += s0_24; - c0_24 = CLAMP (c0_24, 0, 16777216); - len -= 1; - } - } - } -} diff --git a/src/libnrtype/RasterFont.h b/src/libnrtype/RasterFont.h deleted file mode 100644 index 015121b42..000000000 --- a/src/libnrtype/RasterFont.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * RasterFont.h - * testICU - * - */ - -#ifndef my_raster_font -#define my_raster_font - -#include <map> - -#include <libnr/nr-forward.h> -#include <libnrtype/nrtype-forward.h> -#include <libnrtype/font-style.h> - -// one rasterfont is one way to draw a font on the screen -// the way it's drawn is stored in style -class raster_font { -public: - font_instance* daddy; - int refCount; - - font_style style; - - std::map<int,int> glyph_id_to_raster_glyph_no; - // an array of glyphs in this rasterfont. - // it's a bit redundant with the one in the daddy font_instance, but these glyphs - // contains the real rasterization data - int nbBase,maxBase; - raster_glyph** bases; - - explicit raster_font(font_style const &fstyle); - virtual ~raster_font(void); - - void Unref(void); - void Ref(void); - - // utility functions - Geom::Point Advance(int glyph_id); - void BBox(int glyph_id,NRRect *area); - - // attempts to load a glyph and return a raster_glyph on which you can call Blit - raster_glyph* GetGlyph(int glyph_id); - // utility - void LoadRasterGlyph(int glyph_id); // refreshes outline/polygon if needed - void RemoveRasterGlyph(raster_glyph* who); - -private: - /* Disable the default copy constructor and operator=: they do the wrong thing for refCount. */ - raster_font(raster_font const &); - raster_font &operator=(raster_font const &); -}; - -#endif - - -/* - 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 : diff --git a/src/libnrtype/font-glyph.h b/src/libnrtype/font-glyph.h index 234502f9d..14da5025b 100644 --- a/src/libnrtype/font-glyph.h +++ b/src/libnrtype/font-glyph.h @@ -11,7 +11,6 @@ struct font_glyph { double v_advance, v_width; double bbox[4]; // bbox of the path (and the artbpath), not the bbox of the glyph // as the fonts sometimes contain - Path* outline; // outline as a livarot Path Geom::PathVector* pathvector; // outline as 2geom pathvector, for text->curve stuff (should be unified with livarot) }; diff --git a/src/libnrtype/font-instance.h b/src/libnrtype/font-instance.h index 33085858b..392ac20bf 100644 --- a/src/libnrtype/font-instance.h +++ b/src/libnrtype/font-instance.h @@ -55,9 +55,6 @@ public: // nota: all coordinates returned by these functions are on a [0..1] scale; you need to multiply // by the fontsize to get the real sizes - Path* Outline(int glyph_id, Path *copyInto=NULL); - // queries the outline of the glyph (in livarot Path form), and copies it into copyInto instead - // of allocating a new Path if copyInto != NULL Geom::PathVector* PathVector(int glyph_id); // returns the 2geom-type pathvector for this glyph. no refcounting needed, it's deallocated when the font_instance dies double Advance(int glyph_id, bool vertical); @@ -67,15 +64,6 @@ public: // for generating slanted cursors for oblique fonts Geom::OptRect BBox(int glyph_id); - // creates a rasterfont for the given style - raster_font* RasterFont(Geom::Affine const &trs, double stroke_width, - bool vertical = false, JoinType stroke_join = join_straight, - ButtType stroke_cap = butt_straight, float miter_limit = 4.0); - // the dashes array in iStyle is copied - raster_font* RasterFont(font_style const &iStyle); - // private use: tells the font_instance that the raster_font 'who' has died - void RemoveRasterFont(raster_font *who); - // attribute queries unsigned Name(gchar *str, unsigned size); unsigned PSName(gchar *str, unsigned size); @@ -85,9 +73,6 @@ public: private: void FreeTheFace(); - // hashmap to get the raster_font for a given style - void* loadedPtr; - #ifdef USE_PANGO_WIN32 HFONT theFace; #else diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index a7160f5f0..bbed89b55 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -2,10 +2,7 @@ # include <config.h> #endif -#include <libnr/nr-blit.h> #include <libnrtype/font-instance.h> -#include <libnrtype/raster-glyph.h> -#include <libnrtype/RasterFont.h> #include <libnrtype/TextWrapper.h> #include <libnrtype/one-glyph.h> diff --git a/src/libnrtype/nrtype-forward.h b/src/libnrtype/nrtype-forward.h index f3344f2fd..6050ffa6b 100644 --- a/src/libnrtype/nrtype-forward.h +++ b/src/libnrtype/nrtype-forward.h @@ -5,9 +5,6 @@ class font_factory; struct font_glyph; class font_instance; struct font_style; -class raster_font; -class raster_glyph; -class raster_position; #endif /* !SEEN_LIBNRTYPE_NRTYPE_FORWARD_H */ diff --git a/src/libnrtype/raster-glyph.h b/src/libnrtype/raster-glyph.h deleted file mode 100644 index 82a0b3f8e..000000000 --- a/src/libnrtype/raster-glyph.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef SEEN_LIBNRTYPE_RASTER_GLYPH_H -#define SEEN_LIBNRTYPE_RASTER_GLYPH_H - -#include <libnr/nr-forward.h> -#include <libnrtype/nrtype-forward.h> -#include <livarot/livarot-forward.h> - -// a little utility class that holds data to render a styled glyph -// ie. it's like a polygon. its function is to wrap the subpixel positionning -class raster_glyph { -public: - // raster_font that created me - raster_font* daddy; - // the glyph i am (the style is in daddy) - int glyph_id; - // internal structure: the styled path, and the associated uncrossed polygon - // they could be removed after the raster_position have been computed - Path* outline; // transformed by the matrix in style (may be factorized, but is small) - Shape* polygon; - // subpixel positions - // nb_sub_pixel is set to 4 when the glyph is created (it's hardcoded) - int nb_sub_pixel; - raster_position* sub_pixel; - - raster_glyph(void); - virtual ~raster_glyph(void); - - // utility - void SetSubPixelPositionning(int nb_pos); - void LoadSubPixelPosition(int no); - - // the interesting function: blits the glyph onto over - // over should be a mask, ie a NRPixBlock with one 8bit plane - void Blit(Geom::Point const &at, NRPixBlock &over); // alpha only -}; - - -#endif /* !SEEN_LIBNRTYPE_RASTER_GLYPH_H */ - -/* - 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 : diff --git a/src/libnrtype/raster-position.h b/src/libnrtype/raster-position.h deleted file mode 100644 index 744b6dddd..000000000 --- a/src/libnrtype/raster-position.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef SEEN_LIBNRTYPE_RASTER_POSITION_H -#define SEEN_LIBNRTYPE_RASTER_POSITION_H - -#include <vector> - -#include <libnr/nr-forward.h> -#include <libnrtype/nrtype-forward.h> -#include <livarot/livarot-forward.h> - -// one subpixel position -// it's basically a set of trapezoids (=float_ligne_run) representing the black areas of the glyph -// all trapezoids are in the same array, hence the run_on_line array to give the number of -// trapezoids on each line -// trapezoids store the x-positions as float, and are shifted to the x blit position -// so it's "exact" in the x direction and subpixel in the y direction -class raster_position { -public: - int top, bottom; // baseline is y=0 - // top is the first pixel, bottom is the last - int* run_on_line; // array of size (bottom-top+1): run_on_line[i] gives the number of runs on line top+i - int nbRun; - float_ligne_run* runs; - -public: - raster_position(); - virtual ~raster_position(); - - // stuff runs into the structure - void AppendRuns(std::vector<float_ligne_run> const &r, int y); - // blits the trapezoids. - void Blit(float ph, int pv, NRPixBlock &over); -}; - - -#endif /* !SEEN_LIBNRTYPE_RASTER_POSITION_H */ - -/* - 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 : diff --git a/src/livarot/Path.cpp b/src/livarot/Path.cpp index 1c04dbfb1..88d397864 100644 --- a/src/livarot/Path.cpp +++ b/src/livarot/Path.cpp @@ -9,7 +9,6 @@ #include <glib.h> #include "Path.h" #include "livarot/path-description.h" -#include <libnr/nr-matrix-ops.h> /* * manipulation of the path data: path description and polyline diff --git a/src/livarot/PathConversion.cpp b/src/livarot/PathConversion.cpp index bf1e9c5c9..57609d1a2 100644 --- a/src/livarot/PathConversion.cpp +++ b/src/livarot/PathConversion.cpp @@ -9,8 +9,6 @@ #include "Path.h" #include "Shape.h" #include "livarot/path-description.h" - -#include <libnr/nr-matrix.h> #include <2geom/transforms.h> /* diff --git a/src/livarot/PathCutting.cpp b/src/livarot/PathCutting.cpp index ba81864a8..708d20f3f 100644 --- a/src/livarot/PathCutting.cpp +++ b/src/livarot/PathCutting.cpp @@ -20,7 +20,6 @@ #include "Path.h" #include "style.h" #include "livarot/path-description.h" -#include "libnr/nr-point-matrix-ops.h" #include "libnr/nr-convert2geom.h" #include <2geom/pathvector.h> #include <2geom/point.h> @@ -511,10 +510,10 @@ double Path::Surface() for (std::vector<path_lineto>::const_iterator i = pts.begin(); i != pts.end(); i++) { if ( i->isMoveTo == polyline_moveto ) { - surf += NR::cross(lastM - lastP, lastM); + surf += Geom::cross(lastM - lastP, lastM); lastP = lastM = i->p; } else { - surf += NR::cross(i->p - lastP, i->p); + surf += Geom::cross(i->p - lastP, i->p); lastP = i->p; } diff --git a/src/livarot/PathSimplify.cpp b/src/livarot/PathSimplify.cpp index 7b04f028a..fb2aa55e2 100644 --- a/src/livarot/PathSimplify.cpp +++ b/src/livarot/PathSimplify.cpp @@ -7,7 +7,6 @@ */ #include <glib/gmem.h> -#include <libnr/nr-point-matrix-ops.h> #include "livarot/Path.h" #include "livarot/path-description.h" @@ -127,7 +126,7 @@ double DistanceToCubic(Geom::Point const &start, PathDescrCubicTo res, Geom::Poi } Geom::Point seg = res.p - start; - nnle = NR::cross(seg, sp); + nnle = Geom::cross(seg, sp); nnle *= nnle; nnle /= Geom::dot(seg, seg); if ( nnle < nle ) { diff --git a/src/livarot/ShapeMisc.cpp b/src/livarot/ShapeMisc.cpp index 7d23913c3..da268910f 100644 --- a/src/livarot/ShapeMisc.cpp +++ b/src/livarot/ShapeMisc.cpp @@ -7,14 +7,14 @@ */ #include "livarot/Shape.h" -#include <libnr/nr-matrix-fns.h> -#include <libnr/nr-point-fns.h> #include "livarot/Path.h" #include "livarot/path-description.h" #include <glib.h> #include <cstdio> #include <cstdlib> #include <cstring> +#include <2geom/point.h> +#include <2geom/affine.h> /* * polygon offset and polyline to path reassembling (when using back data) diff --git a/src/livarot/ShapeSweep.cpp b/src/livarot/ShapeSweep.cpp index a0b9dac1d..e3fb0296d 100644 --- a/src/livarot/ShapeSweep.cpp +++ b/src/livarot/ShapeSweep.cpp @@ -9,14 +9,14 @@ #include <cstdio> #include <cstdlib> #include <cstring> +#include <glib.h> #include <glib/gmem.h> +#include <2geom/affine.h> #include "Shape.h" #include "livarot/sweep-event-queue.h" #include "livarot/sweep-tree-list.h" #include "livarot/sweep-tree.h" -#include "libnr/nr-matrix.h" - //int doDebug=0; /* diff --git a/src/livarot/path-description.cpp b/src/livarot/path-description.cpp index 95bd192d5..c34965a5c 100644 --- a/src/livarot/path-description.cpp +++ b/src/livarot/path-description.cpp @@ -1,5 +1,5 @@ -#include "libnr/nr-point-matrix-ops.h" #include "livarot/path-description.h" +#include <2geom/affine.h> PathDescr *PathDescrMoveTo::clone() const { diff --git a/src/live_effects/lpe-curvestitch.cpp b/src/live_effects/lpe-curvestitch.cpp index a2b4a591a..a002901b2 100644 --- a/src/live_effects/lpe-curvestitch.cpp +++ b/src/live_effects/lpe-curvestitch.cpp @@ -58,7 +58,7 @@ LPECurveStitch::LPECurveStitch(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast<Parameter *>(&scale_y_rel) ); nrofpaths.param_make_integer(); - nrofpaths.param_set_range(2, NR_HUGE); + nrofpaths.param_set_range(2, Geom::infinity()); prop_scale.param_set_digits(3); prop_scale.param_set_increments(0.01, 0.10); diff --git a/src/live_effects/lpe-dynastroke.cpp b/src/live_effects/lpe-dynastroke.cpp index 97d49d83d..0fd31dccf 100644 --- a/src/live_effects/lpe-dynastroke.cpp +++ b/src/live_effects/lpe-dynastroke.cpp @@ -97,11 +97,11 @@ LPEDynastroke::LPEDynastroke(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast<Parameter *>(& round_ends) ); registerParameter( dynamic_cast<Parameter *>(& capping) ); - width.param_set_range(0, NR_HUGE); + width.param_set_range(0, Geom::infinity()); roundness.param_set_range(0.01, 1); angle.param_set_range(-360, 360); - growfor.param_set_range(0, NR_HUGE); - fadefor.param_set_range(0, NR_HUGE); + growfor.param_set_range(0, Geom::infinity()); + fadefor.param_set_range(0, Geom::infinity()); show_orig_path = true; } diff --git a/src/live_effects/lpe-interpolate.cpp b/src/live_effects/lpe-interpolate.cpp index b8ce721a1..621823546 100644 --- a/src/live_effects/lpe-interpolate.cpp +++ b/src/live_effects/lpe-interpolate.cpp @@ -38,7 +38,7 @@ LPEInterpolate::LPEInterpolate(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast<Parameter *>(&number_of_steps) ); number_of_steps.param_make_integer(); - number_of_steps.param_set_range(2, NR_HUGE); + number_of_steps.param_set_range(2, Geom::infinity()); } LPEInterpolate::~LPEInterpolate() diff --git a/src/live_effects/lpe-patternalongpath.cpp b/src/live_effects/lpe-patternalongpath.cpp index b1af4c149..0a05228d2 100644 --- a/src/live_effects/lpe-patternalongpath.cpp +++ b/src/live_effects/lpe-patternalongpath.cpp @@ -139,9 +139,9 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con } //TODO: dynamical update of parameter ranges? //if (prop_units.get_value()){ - // spacing.param_set_range(-.9, NR_HUGE); + // spacing.param_set_range(-.9, Geom::infinity()); // }else{ - // spacing.param_set_range(-pattBndsX.extent()*.9, NR_HUGE); + // spacing.param_set_range(-pattBndsX.extent()*.9, Geom::infinity()); // } y0+=noffset; diff --git a/src/live_effects/lpe-rough-hatches.cpp b/src/live_effects/lpe-rough-hatches.cpp index 055b63661..671d88a8b 100644 --- a/src/live_effects/lpe-rough-hatches.cpp +++ b/src/live_effects/lpe-rough-hatches.cpp @@ -271,13 +271,13 @@ LPERoughHatches::LPERoughHatches(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast<Parameter *>(&front_thickness) ); registerParameter( dynamic_cast<Parameter *>(&back_thickness) ); - //hatch_dist.param_set_range(0.1, NR_HUGE); - growth.param_set_range(0, NR_HUGE); + //hatch_dist.param_set_range(0.1, Geom::infinity()); + growth.param_set_range(0, Geom::infinity()); dist_rdm.param_set_range(0, 99.); - stroke_width_top.param_set_range(0, NR_HUGE); - stroke_width_bot.param_set_range(0, NR_HUGE); - front_thickness.param_set_range(0, NR_HUGE); - back_thickness.param_set_range(0, NR_HUGE); + stroke_width_top.param_set_range(0, Geom::infinity()); + stroke_width_bot.param_set_range(0, Geom::infinity()); + front_thickness.param_set_range(0, Geom::infinity()); + back_thickness.param_set_range(0, Geom::infinity()); // hide the widgets for direction and bender vectorparams direction.widget_is_visible = false; diff --git a/src/live_effects/lpe-sketch.cpp b/src/live_effects/lpe-sketch.cpp index 9488da84a..b621f6eca 100644 --- a/src/live_effects/lpe-sketch.cpp +++ b/src/live_effects/lpe-sketch.cpp @@ -89,24 +89,24 @@ LPESketch::LPESketch(LivePathEffectObject *lpeobject) : #endif nbiter_approxstrokes.param_make_integer(); - nbiter_approxstrokes.param_set_range(0, NR_HUGE); - strokelength.param_set_range(1, NR_HUGE); + nbiter_approxstrokes.param_set_range(0, Geom::infinity()); + strokelength.param_set_range(1, Geom::infinity()); strokelength.param_set_increments(1., 5.); strokelength_rdm.param_set_range(0, 1.); strokeoverlap.param_set_range(0, 1.); strokeoverlap.param_set_increments(0.1, 0.30); ends_tolerance.param_set_range(0., 1.); - parallel_offset.param_set_range(0, NR_HUGE); + parallel_offset.param_set_range(0, Geom::infinity()); tremble_frequency.param_set_range(0.01, 100.); tremble_frequency.param_set_increments(.5, 1.5); strokeoverlap_rdm.param_set_range(0, 1.); #ifdef LPE_SKETCH_USE_CONSTRUCTION_LINES nbtangents.param_make_integer(); - nbtangents.param_set_range(0, NR_HUGE); - tgtscale.param_set_range(0, NR_HUGE); + nbtangents.param_set_range(0, Geom::infinity()); + tgtscale.param_set_range(0, Geom::infinity()); tgtscale.param_set_increments(.1, .5); - tgtlength.param_set_range(0, NR_HUGE); + tgtlength.param_set_range(0, Geom::infinity()); tgtlength.param_set_increments(1., 5.); tgtlength_rdm.param_set_range(0, 1.); tgt_places_rdmness.param_set_range(0, 1.); diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp index 050e4adc2..56e73e3a3 100644 --- a/src/live_effects/lpe-vonkoch.cpp +++ b/src/live_effects/lpe-vonkoch.cpp @@ -66,9 +66,9 @@ LPEVonKoch::LPEVonKoch(LivePathEffectObject *lpeobject) : //registerParameter( dynamic_cast<Parameter *>(&draw_boxes) ); nbgenerations.param_make_integer(); - nbgenerations.param_set_range(0, NR_HUGE); + nbgenerations.param_set_range(0, Geom::infinity()); maxComplexity.param_make_integer(); - maxComplexity.param_set_range(0, NR_HUGE); + maxComplexity.param_set_range(0, Geom::infinity()); } LPEVonKoch::~LPEVonKoch() diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp index 57d583ba6..fc15ce1f5 100644 --- a/src/live_effects/parameter/parameter.cpp +++ b/src/live_effects/parameter/parameter.cpp @@ -53,8 +53,8 @@ ScalarParam::ScalarParam( const Glib::ustring& label, const Glib::ustring& tip, Effect* effect, gdouble default_value) : Parameter(label, tip, key, wr, effect), value(default_value), - min(-NR_HUGE), - max(NR_HUGE), + min(-Geom::infinity()), + max(Geom::infinity()), integer(false), defvalue(default_value), digits(2), diff --git a/src/live_effects/parameter/random.cpp b/src/live_effects/parameter/random.cpp index 889e5375b..cdfb1fb50 100644 --- a/src/live_effects/parameter/random.cpp +++ b/src/live_effects/parameter/random.cpp @@ -32,8 +32,8 @@ RandomParam::RandomParam( const Glib::ustring& label, const Glib::ustring& tip, { defvalue = default_value; value = defvalue; - min = -NR_HUGE; - max = NR_HUGE; + min = -Geom::infinity(); + max = Geom::infinity(); integer = false; defseed = default_seed; diff --git a/src/main.cpp b/src/main.cpp index 8ed6b4c03..26774fd66 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -96,9 +96,8 @@ #include <extension/input.h> #ifdef WIN32 +#include <windows.h> #include "registrytool.h" -#include "extension/internal/win32.h" -using Inkscape::Extension::Internal::PrintWin32; #endif // WIN32 #include "extension/init.h" @@ -698,9 +697,6 @@ main(int argc, char **argv) } #ifdef WIN32 -#ifndef REPLACEARGS_ANSI - if ( PrintWin32::is_os_wide() ) -#endif // REPLACEARGS_ANSI { // If the call fails, we'll need to convert charsets needToRecodeParams = !replaceArgs( argc, argv ); diff --git a/src/marker.cpp b/src/marker.cpp index 5dd23fb1e..e82d3d952 100644 --- a/src/marker.cpp +++ b/src/marker.cpp @@ -17,12 +17,6 @@ #include <string> #include "config.h" - -#include "libnr/nr-matrix-fns.h" -#include "libnr/nr-matrix-ops.h" -#include "libnr/nr-matrix-translate-ops.h" -#include "libnr/nr-scale-matrix-ops.h" -#include "libnr/nr-translate-matrix-ops.h" #include "libnr/nr-convert2geom.h" #include <2geom/affine.h> #include "svg/svg.h" @@ -621,6 +615,13 @@ sp_marker_show_instance ( SPMarker *marker, NRArenaItem *parent, unsigned int key, unsigned int pos, Geom::Affine const &base, float linewidth) { + // do not show marker if linewidth == 0 and markerUnits == strokeWidth + // otherwise Cairo will fail to render anything on the tile + // that contains the "degenerate" marker + if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH && linewidth == 0) { + return NULL; + } + for (SPMarkerView *v = marker->views; v != NULL; v = v->next) { if (v->key == key) { if (pos >= v->items.size()) { diff --git a/src/object-edit.cpp b/src/object-edit.cpp index 2b03d7654..553c125a3 100644 --- a/src/object-edit.cpp +++ b/src/object-edit.cpp @@ -30,18 +30,11 @@ #include "desktop-handles.h" #include "sp-namedview.h" #include "live_effects/effect.h" - #include "sp-pattern.h" #include "sp-path.h" - #include <glibmm/i18n.h> - #include "object-edit.h" - -#include <libnr/nr-scale-ops.h> - #include "xml/repr.h" - #include "2geom/isnan.h" #define sp_round(v,m) (((v) < 0.0) ? ((ceil((v) / (m) - 0.5)) * (m)) : ((floor((v) / (m) + 0.5)) * (m))) diff --git a/src/preferences-skeleton.h b/src/preferences-skeleton.h index 62744bd53..16723170f 100644 --- a/src/preferences-skeleton.h +++ b/src/preferences-skeleton.h @@ -345,7 +345,6 @@ static char const preferences_skeleton[] = " colorsontop=\"0\"\n" " floatallowed=\"0\"\n" " partialdynamic=\"0\"/>\n" -" <group id=\"threading\" numthreads=\"1\"/>\n" " </group>\n" "\n" " <group id=\"extensions\">" diff --git a/src/print.cpp b/src/print.cpp index fe52ea6dd..0774f5751 100644 --- a/src/print.cpp +++ b/src/print.cpp @@ -85,43 +85,6 @@ unsigned int sp_print_text(SPPrintContext *ctx, char const *text, Geom::Point p, /* UI */ void -sp_print_preview_document(SPDocument *doc) -{ - Inkscape::Extension::Print *mod; - unsigned int ret; - - doc->ensureUpToDate(); - - mod = Inkscape::Extension::get_print(SP_MODULE_KEY_PRINT_DEFAULT); - - ret = mod->set_preview(); - - if (ret) { - SPPrintContext context; - context.module = mod; - - /* fixme: This has to go into module constructor somehow */ - /* Create new arena */ - mod->base = SP_ITEM(doc->getRoot()); - mod->arena = NRArena::create(); - mod->dkey = SPItem::display_key_new(1); - mod->root = (mod->base)->invoke_show(mod->arena, mod->dkey, SP_ITEM_SHOW_DISPLAY); - /* Print document */ - ret = mod->begin(doc); - (mod->base)->invoke_print(&context); - ret = mod->finish(); - /* Release arena */ - (mod->base)->invoke_hide(mod->dkey); - mod->base = NULL; - mod->root = NULL; - nr_object_unref((NRObject *) mod->arena); - mod->arena = NULL; - } - - return; -} - -void sp_print_document(Gtk::Window& parentWindow, SPDocument *doc) { doc->ensureUpToDate(); diff --git a/src/print.h b/src/print.h index 70361fb14..caea6ae3a 100644 --- a/src/print.h +++ b/src/print.h @@ -41,7 +41,6 @@ void sp_print_get_param(SPPrintContext *ctx, gchar *name, bool *value); /* UI */ -void sp_print_preview_document(SPDocument *doc); void sp_print_document(Gtk::Window& parentWindow, SPDocument *doc); void sp_print_document_to_file(SPDocument *doc, gchar const *filename); diff --git a/src/proj_pt.cpp b/src/proj_pt.cpp index 1d308f847..d9d4e06f1 100644 --- a/src/proj_pt.cpp +++ b/src/proj_pt.cpp @@ -48,7 +48,7 @@ Pt2::normalize() { Geom::Point Pt2::affine() { if (fabs(pt[2]) < epsilon) { - return Geom::Point (NR_HUGE, NR_HUGE); + return Geom::Point (Geom::infinity(), Geom::infinity()); } return Geom::Point (pt[0]/pt[2], pt[1]/pt[2]); } diff --git a/src/proj_pt.h b/src/proj_pt.h index 90f4af652..90b9df201 100644 --- a/src/proj_pt.h +++ b/src/proj_pt.h @@ -13,7 +13,6 @@ */ #include <2geom/point.h> -#include "libnr/nr-values.h" #include <gtk/gtk.h> namespace Proj { @@ -29,12 +28,12 @@ public: Pt2 (const gchar *coord_str); inline double operator[] (unsigned int index) const { - if (index > 2) { return NR_HUGE; } + if (index > 2) { return Geom::infinity(); } return pt[index]; } inline double &operator[] (unsigned int index) { // FIXME: How should we handle wrong indices? - //if (index > 2) { return NR_HUGE; } + //if (index > 2) { return Geom::infinity(); } return pt[index]; } inline bool operator== (Pt2 &rhs) { @@ -137,12 +136,12 @@ public: } inline double operator[] (unsigned int index) const { - if (index > 3) { return NR_HUGE; } + if (index > 3) { return Geom::infinity(); } return pt[index]; } inline double &operator[] (unsigned int index) { // FIXME: How should we handle wrong indices? - //if (index > 3) { return NR_HUGE; } + //if (index > 3) { return Geom::infinity(); } return pt[index]; } void normalize(); diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 0f756a9a3..6f385b8f5 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -53,10 +53,6 @@ SPCycleType SP_CYCLING = SP_CYCLE_FOCUS; #include "sp-conn-end.h" #include "dropper-context.h" #include <glibmm/i18n.h> -#include "libnr/nr-matrix-rotate-ops.h" -#include "libnr/nr-matrix-translate-ops.h" -#include "libnr/nr-scale-ops.h" -#include <libnr/nr-matrix-ops.h> #include <2geom/transforms.h> #include "xml/repr.h" #include "xml/rebase-hrefs.h" @@ -1054,7 +1050,7 @@ take_style_from_item(SPItem *item) } // FIXME: also transform gradient/pattern fills, by forking? NO, this must be nondestructive - double ex = to_2geom(item->i2doc_affine()).descrim(); + double ex = item->i2doc_affine().descrim(); if (ex != 1.0) { css = sp_css_attr_scale(css, ex); } @@ -2471,7 +2467,7 @@ sp_selection_tile(SPDesktop *desktop, bool apply) gchar const *pat_id = pattern_tile(repr_copies, bounds, doc, ( Geom::Affine(Geom::Translate(desktop->dt2doc(Geom::Point(r->min()[Geom::X], r->max()[Geom::Y])))) - * to_2geom(parent_transform.inverse()) ), + * parent_transform.inverse() ), parent_transform * move); // restore compensation setting @@ -2481,8 +2477,8 @@ sp_selection_tile(SPDesktop *desktop, bool apply) Inkscape::XML::Node *rect = xml_doc->createElement("svg:rect"); rect->setAttribute("style", g_strdup_printf("stroke:none;fill:url(#%s)", pat_id)); - Geom::Point min = bounds.min() * to_2geom(parent_transform.inverse()); - Geom::Point max = bounds.max() * to_2geom(parent_transform.inverse()); + Geom::Point min = bounds.min() * parent_transform.inverse(); + Geom::Point max = bounds.max() * parent_transform.inverse(); sp_repr_set_svg_double(rect, "width", max[Geom::X] - min[Geom::X]); sp_repr_set_svg_double(rect, "height", max[Geom::Y] - min[Geom::Y]); @@ -2547,7 +2543,7 @@ void sp_selection_untile(SPDesktop *desktop) SPPattern *pattern = pattern_getroot(SP_PATTERN(server)); - Geom::Affine pat_transform = to_2geom(pattern_patternTransform(SP_PATTERN(server))); + Geom::Affine pat_transform = pattern_patternTransform(SP_PATTERN(server)); pat_transform *= item->transform; for (SPObject *child = pattern->firstChild() ; child != NULL; child = child->next ) { @@ -2666,10 +2662,9 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) desktop->setWaitingCursor(); // Get the bounding box of the selection - NRRect bbox; document->ensureUpToDate(); - selection->bounds(&bbox); - if (NR_RECT_DFLS_TEST_EMPTY(&bbox)) { + Geom::OptRect bbox = selection->bounds(); + if (!bbox) { desktop->clearWaitingCursor(); return; // exceptional situation, so not bother with a translatable error message, just quit quietly } @@ -2722,7 +2717,7 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) res = prefs_res; } else if (0 < prefs_min) { // If minsize is given, look up minimum bitmap size (default 250 pixels) and calculate resolution from it - res = PX_PER_IN * prefs_min / MIN((bbox.x1 - bbox.x0), (bbox.y1 - bbox.y0)); + res = PX_PER_IN * prefs_min / MIN(bbox->width(), bbox->height()); } else { float hint_xdpi = 0, hint_ydpi = 0; char const *hint_filename; @@ -2743,8 +2738,8 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) } // The width and height of the bitmap in pixels - unsigned width = (unsigned) floor((bbox.x1 - bbox.x0) * res / PX_PER_IN); - unsigned height =(unsigned) floor((bbox.y1 - bbox.y0) * res / PX_PER_IN); + unsigned width = (unsigned) floor(bbox->width() * res / PX_PER_IN); + unsigned height =(unsigned) floor(bbox->height() * res / PX_PER_IN); // Find out if we have to run an external filter gchar const *run = NULL; @@ -2774,8 +2769,8 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) Geom::Affine eek(SP_ITEM(parent_object)->i2d_affine()); Geom::Affine t; - double shift_x = bbox.x0; - double shift_y = bbox.y1; + double shift_x = bbox->min()[Geom::X]; + double shift_y = bbox->max()[Geom::Y]; if (res == PX_PER_IN) { // for default 90 dpi, snap it to pixel grid shift_x = round(shift_x); shift_y = -round(-shift_y); // this gets correct rounding despite coordinate inversion, remove the negations when the inversion is gone @@ -2784,7 +2779,8 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) // Do the export sp_export_png_file(document, filepath, - bbox.x0, bbox.y0, bbox.x1, bbox.y1, + bbox->min()[Geom::X], bbox->min()[Geom::Y], + bbox->max()[Geom::X], bbox->max()[Geom::Y], width, height, res, res, (guint32) 0xffffff00, NULL, NULL, @@ -2810,8 +2806,8 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) sp_repr_set_svg_double(repr, "width", width); sp_repr_set_svg_double(repr, "height", height); } else { - sp_repr_set_svg_double(repr, "width", (bbox.x1 - bbox.x0)); - sp_repr_set_svg_double(repr, "height", (bbox.y1 - bbox.y0)); + sp_repr_set_svg_double(repr, "width", bbox->width()); + sp_repr_set_svg_double(repr, "height", bbox->height()); } // Write transform diff --git a/src/selection.h b/src/selection.h index de4294a63..00572a1c5 100644 --- a/src/selection.h +++ b/src/selection.h @@ -22,8 +22,6 @@ #include <stddef.h> #include <sigc++/sigc++.h> -//#include "libnr/nr-rect.h" -#include "libnr/nr-convex-hull.h" #include "forward.h" #include "gc-managed.h" #include "gc-finalized.h" diff --git a/src/seltrans.cpp b/src/seltrans.cpp index 061f60896..bb333caca 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -379,9 +379,9 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s } // Now let's reduce this to a single closest snappoint - Geom::Coord dsp = _snap_points.size() == 1 ? Geom::L2((_snap_points.at(0)).getPoint() - p) : NR_HUGE; - Geom::Coord dbbp = _bbox_points.size() == 1 ? Geom::L2((_bbox_points.at(0)).getPoint() - p) : NR_HUGE; - Geom::Coord dbbpft = _bbox_points_for_translating.size() == 1 ? Geom::L2((_bbox_points_for_translating.at(0)).getPoint() - p) : NR_HUGE; + Geom::Coord dsp = _snap_points.size() == 1 ? Geom::L2((_snap_points.at(0)).getPoint() - p) : Geom::infinity(); + Geom::Coord dbbp = _bbox_points.size() == 1 ? Geom::L2((_bbox_points.at(0)).getPoint() - p) : Geom::infinity(); + Geom::Coord dbbpft = _bbox_points_for_translating.size() == 1 ? Geom::L2((_bbox_points_for_translating.at(0)).getPoint() - p) : Geom::infinity(); if (translating) { _bbox_points.clear(); @@ -1219,7 +1219,7 @@ gboolean Inkscape::SelTrans::skewRequest(SPSelTransHandle const &handle, Geom::P if (sn.getSnapped()) { // We snapped something, so change the skew to reflect it - Geom::Coord const sd = sn.getSnapped() ? sn.getTransformation()[0] : NR_HUGE; + Geom::Coord const sd = sn.getSnapped() ? sn.getTransformation()[0] : Geom::infinity(); _desktop->snapindicator->set_new_snaptarget(sn); skew[dim_a] = sd; } else { diff --git a/src/shape-editor.h b/src/shape-editor.h index f400244b3..1f0958a3e 100644 --- a/src/shape-editor.h +++ b/src/shape-editor.h @@ -24,7 +24,6 @@ class SPNodeContext; class ShapeEditorsCollective; class LivePathEffectObject; -#include "libnr/nr-path-code.h" #include <2geom/point.h> #include <boost/optional.hpp> #include <vector> diff --git a/src/snap.cpp b/src/snap.cpp index fb8f70c49..f8fe8e3fa 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -206,7 +206,7 @@ Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::SnapCandidatePoint const Geom::OptRect const &bbox_to_snap) const { if (!someSnapperMightSnap()) { - return Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false); + return Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_UNDEFINED, Geom::infinity(), 0, false, false, false); } SnappedConstraints sc; @@ -263,7 +263,7 @@ Geom::Point SnapManager::multipleOfGridPitch(Geom::Point const &t, Geom::Point c if (_desktop && _desktop->gridsEnabled()) { bool success = false; Geom::Point nearest_multiple; - Geom::Coord nearest_distance = NR_HUGE; + Geom::Coord nearest_distance = Geom::infinity(); Inkscape::SnappedPoint bestSnappedPoint(t); // It will snap to the grid for which we find the closest snap. This might be a different @@ -717,10 +717,10 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( /* The current best transformation */ Geom::Point best_transformation = transformation; - /* The current best metric for the best transformation; lower is better, NR_HUGE + /* The current best metric for the best transformation; lower is better, Geom::infinity() ** means that we haven't snapped anything. */ - Geom::Point best_scale_metric(NR_HUGE, NR_HUGE); + Geom::Point best_scale_metric(Geom::infinity(), Geom::infinity()); Inkscape::SnappedPoint best_snapped_point; g_assert(best_snapped_point.getAlwaysSnap() == false); // Check initialization of snapped point g_assert(best_snapped_point.getAtIntersection() == false); @@ -929,10 +929,10 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( Geom::Coord best_metric; if (transformation_type == SCALE) { - // When scaling, don't ever exit with one of scaling components set to NR_HUGE + // When scaling, don't ever exit with one of scaling components set to Geom::infinity() for (int index = 0; index < 2; index++) { - if (best_transformation[index] == NR_HUGE) { - if (uniform && best_transformation[1-index] < NR_HUGE) { + if (best_transformation[index] == Geom::infinity()) { + if (uniform && best_transformation[1-index] < Geom::infinity()) { best_transformation[index] = best_transformation[1-index]; } else { best_transformation[index] = transformation[index]; @@ -943,9 +943,9 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( best_metric = best_snapped_point.getSnapDistance(); best_snapped_point.setTransformation(best_transformation); - // Using " < 1e6" instead of " < NR_HUGE" for catching some rounding errors + // Using " < 1e6" instead of " < Geom::infinity()" for catching some rounding errors // These rounding errors might be caused by NRRects, see bug #1584301 - best_snapped_point.setSnapDistance(best_metric < 1e6 ? best_metric : NR_HUGE); + best_snapped_point.setSnapDistance(best_metric < 1e6 ? best_metric : Geom::infinity()); if (_snapindicator) { if (best_snapped_point.getSnapped()) { @@ -954,7 +954,6 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( _desktop->snapindicator->remove_snaptarget(); } } - return best_snapped_point; } diff --git a/src/snapped-curve.cpp b/src/snapped-curve.cpp index 25bde8105..4876b896d 100644 --- a/src/snapped-curve.cpp +++ b/src/snapped-curve.cpp @@ -20,7 +20,7 @@ Inkscape::SnappedCurve::SnappedCurve(Geom::Point const &snapped_point, int num_p _tolerance = std::max(snapped_tolerance, 1.0); _always_snap = always_snap; _curve = curve; - _second_distance = NR_HUGE; + _second_distance = Geom::infinity(); _second_tolerance = 1; _second_always_snap = false; _point = snapped_point; @@ -36,11 +36,11 @@ Inkscape::SnappedCurve::SnappedCurve() { _num_path = 0; _num_segm = 0; - _distance = NR_HUGE; + _distance = Geom::infinity(); _tolerance = 1; _always_snap = false; _curve = NULL; - _second_distance = NR_HUGE; + _second_distance = Geom::infinity(); _second_tolerance = 1; _second_always_snap = false; _point = Geom::Point(0,0); @@ -67,8 +67,8 @@ Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &cur if (cs.size() > 0) { // There might be multiple intersections: find the closest - Geom::Coord best_dist = NR_HUGE; - Geom::Point best_p = Geom::Point(NR_HUGE, NR_HUGE); + Geom::Coord best_dist = Geom::infinity(); + Geom::Point best_p = Geom::Point(Geom::infinity(), Geom::infinity()); for (Geom::Crossings::const_iterator i = cs.begin(); i != cs.end(); i++) { Geom::Point p_ix = this->_curve->pointAt((*i).ta); Geom::Coord dist = Geom::distance(p_ix, p); @@ -106,7 +106,7 @@ Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &cur } // No intersection - return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, false, NR_HUGE, 0, false); + return SnappedPoint(Geom::Point(Geom::infinity(), Geom::infinity()), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, Geom::infinity(), 0, false, false, false, false, Geom::infinity(), 0, false); } // search for the closest snapped line diff --git a/src/snapped-line.cpp b/src/snapped-line.cpp index 090eadf0a..525208f06 100644 --- a/src/snapped-line.cpp +++ b/src/snapped-line.cpp @@ -22,7 +22,7 @@ Inkscape::SnappedLineSegment::SnappedLineSegment(Geom::Point const &snapped_poin _tolerance = std::max(snapped_tolerance, 1.0); _always_snap = always_snap; _at_intersection = false; - _second_distance = NR_HUGE; + _second_distance = Geom::infinity(); _second_tolerance = 1; _second_always_snap = false; } @@ -35,11 +35,11 @@ Inkscape::SnappedLineSegment::SnappedLineSegment() _source = SNAPSOURCE_UNDEFINED; _source_num = -1; _target = SNAPTARGET_UNDEFINED; - _distance = NR_HUGE; + _distance = Geom::infinity(); _tolerance = 1; _always_snap = false; _at_intersection = false; - _second_distance = NR_HUGE; + _second_distance = Geom::infinity(); _second_tolerance = 1; _second_always_snap = false; } @@ -85,7 +85,7 @@ Inkscape::SnappedPoint Inkscape::SnappedLineSegment::intersect(SnappedLineSegmen } // No intersection - return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, false, NR_HUGE, 0, false); + return SnappedPoint(Geom::Point(Geom::infinity(), Geom::infinity()), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, Geom::infinity(), 0, false, false, false, false, Geom::infinity(), 0, false); }; @@ -99,7 +99,7 @@ Inkscape::SnappedLine::SnappedLine(Geom::Point const &snapped_point, Geom::Coord _distance = snapped_distance; _tolerance = std::max(snapped_tolerance, 1.0); _always_snap = always_snap; - _second_distance = NR_HUGE; + _second_distance = Geom::infinity(); _second_tolerance = 1; _second_always_snap = false; _point = snapped_point; @@ -113,10 +113,10 @@ Inkscape::SnappedLine::SnappedLine() _source = SNAPSOURCE_UNDEFINED; _source_num = -1; _target = SNAPTARGET_UNDEFINED; - _distance = NR_HUGE; + _distance = Geom::infinity(); _tolerance = 1; _always_snap = false; - _second_distance = NR_HUGE; + _second_distance = Geom::infinity(); _second_tolerance = 1; _second_always_snap = false; _point = Geom::Point(0,0); @@ -168,7 +168,7 @@ Inkscape::SnappedPoint Inkscape::SnappedLine::intersect(SnappedLine const &line) } // No intersection - return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, false, NR_HUGE, 0, false); + return SnappedPoint(Geom::Point(Geom::infinity(), Geom::infinity()), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, Geom::infinity(), 0, false, false, false, false, Geom::infinity(), 0, false); } // search for the closest snapped line segment diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index 52f0a7839..2db3d62e4 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -21,11 +21,11 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const _at_intersection = false; _constrained_snap = constrained_snap; _fully_constrained = fully_constrained; - _second_distance = NR_HUGE; + _second_distance = Geom::infinity(); _second_tolerance = 1; _second_always_snap = false; _transformation = Geom::Point(1,1); - _pointer_distance = NR_HUGE; + _pointer_distance = Geom::infinity(); } Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained) @@ -37,11 +37,11 @@ Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, Snap _at_intersection = false; _constrained_snap = constrained_snap; _fully_constrained = fully_constrained; - _second_distance = NR_HUGE; + _second_distance = Geom::infinity(); _second_tolerance = 1; _second_always_snap = false; _transformation = Geom::Point(1,1); - _pointer_distance = NR_HUGE; + _pointer_distance = Geom::infinity(); _target_bbox = p.getTargetBBox(); } @@ -53,7 +53,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const // tolerance should never be smaller than 1 px, as it is used for normalization in // isOtherSnapBetter. We don't want a division by zero. _transformation = Geom::Point(1,1); - _pointer_distance = NR_HUGE; + _pointer_distance = Geom::infinity(); _target_bbox = Geom::OptRect(); } @@ -66,14 +66,14 @@ Inkscape::SnappedPoint::SnappedPoint() _at_intersection = false; _constrained_snap = false; _fully_constrained = false; - _distance = NR_HUGE; + _distance = Geom::infinity(); _tolerance = 1; _always_snap = false; - _second_distance = NR_HUGE; + _second_distance = Geom::infinity(); _second_tolerance = 1; _second_always_snap = false; _transformation = Geom::Point(1,1); - _pointer_distance = NR_HUGE; + _pointer_distance = Geom::infinity(); _target_bbox = Geom::OptRect(); } @@ -85,14 +85,14 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p) _target = SNAPTARGET_UNDEFINED, _at_intersection = false; _fully_constrained = false; - _distance = NR_HUGE; + _distance = Geom::infinity(); _tolerance = 1; _always_snap = false; - _second_distance = NR_HUGE; + _second_distance = Geom::infinity(); _second_tolerance = 1; _second_always_snap = false; _transformation = Geom::Point(1,1); - _pointer_distance = NR_HUGE; + _pointer_distance = Geom::infinity(); _target_bbox = Geom::OptRect(); } @@ -152,7 +152,7 @@ bool Inkscape::SnappedPoint::isOtherSnapBetter(Inkscape::SnappedPoint const &oth // When accounting for the distance to the mouse pointer, then at least one of the snapped points should // have that distance set. If not, then this is a bug. Either "weighted" must be set to false, or the // mouse pointer distance must be set. - g_assert(dist_pointer_this != NR_HUGE || dist_pointer_other != NR_HUGE); + g_assert(dist_pointer_this != Geom::infinity() || dist_pointer_other != Geom::infinity()); // The snap distance will always be smaller than the tolerance set for the snapper. The pointer distance can // however be very large. To compare these in a fair way, we will have to normalize these metrics first // The closest pointer distance will be normalized to 1.0; the other one will be > 1.0 @@ -195,7 +195,7 @@ bool Inkscape::SnappedPoint::isOtherSnapBetter(Inkscape::SnappedPoint const &oth // or, if it's just as close then consider the second distance ... bool c5a = (dist_other == dist_this); - bool c5b = (other_one.getSecondSnapDistance() < getSecondSnapDistance()) && (getSecondSnapDistance() < NR_HUGE); + bool c5b = (other_one.getSecondSnapDistance() < getSecondSnapDistance()) && (getSecondSnapDistance() < Geom::infinity()); // ... or prefer free snaps over constrained snaps bool c5c = !other_one.getConstrainedSnap() && getConstrainedSnap(); diff --git a/src/snapped-point.h b/src/snapped-point.h index b2a9fa1ce..7dc6edeca 100644 --- a/src/snapped-point.h +++ b/src/snapped-point.h @@ -14,7 +14,6 @@ #include <vector> #include <list> -#include <libnr/nr-values.h> //Because of NR_HUGE #include <2geom/geom.h> #include <snap-candidate.h> @@ -64,7 +63,7 @@ public: bool getAtIntersection() const {return _at_intersection;} bool getFullyConstrained() const {return _fully_constrained;} bool getConstrainedSnap() const {return _constrained_snap;} - bool getSnapped() const {return _distance < NR_HUGE;} + bool getSnapped() const {return _distance < Geom::infinity();} Geom::Point getTransformation() const {return _transformation;} void setTransformation(Geom::Point const t) {_transformation = t;} void setTarget(SnapTargetType const target) {_target = target;} diff --git a/src/sp-clippath.cpp b/src/sp-clippath.cpp index 89e140f12..147ece167 100644 --- a/src/sp-clippath.cpp +++ b/src/sp-clippath.cpp @@ -25,7 +25,6 @@ #include "document-private.h" #include "sp-item.h" -#include "libnr/nr-matrix-ops.h" #include <2geom/transforms.h> #include "sp-clippath.h" @@ -286,10 +285,10 @@ void SPClipPath::setBBox(unsigned int key, NRRect *bbox) { for (SPClipPathView *v = display; v != NULL; v = v->next) { if (v->key == key) { - if (!NR_DF_TEST_CLOSE(v->bbox.x0, bbox->x0, NR_EPSILON) || - !NR_DF_TEST_CLOSE(v->bbox.y0, bbox->y0, NR_EPSILON) || - !NR_DF_TEST_CLOSE(v->bbox.x1, bbox->x1, NR_EPSILON) || - !NR_DF_TEST_CLOSE(v->bbox.y1, bbox->y1, NR_EPSILON)) { + if (!Geom::are_near(v->bbox.x0, bbox->x0) || + !Geom::are_near(v->bbox.y0, bbox->y0) || + !Geom::are_near(v->bbox.x1, bbox->x1) || + !Geom::are_near(v->bbox.y1, bbox->y1)) { v->bbox = *bbox; } break; diff --git a/src/sp-conn-end.cpp b/src/sp-conn-end.cpp index d11eca4c7..538638d7a 100644 --- a/src/sp-conn-end.cpp +++ b/src/sp-conn-end.cpp @@ -4,7 +4,6 @@ #include <limits> #include "display/curve.h" -#include "libnr/nr-matrix-fns.h" #include "xml/repr.h" #include "sp-conn-end.h" #include "sp-path.h" diff --git a/src/sp-ellipse.cpp b/src/sp-ellipse.cpp index cb8c1699b..cf5927fc8 100644 --- a/src/sp-ellipse.cpp +++ b/src/sp-ellipse.cpp @@ -17,8 +17,6 @@ # include "config.h" #endif - -#include "libnr/nr-matrix-fns.h" #include "svg/svg.h" #include "svg/path-string.h" #include "xml/repr.h" diff --git a/src/sp-filter-fns.h b/src/sp-filter-fns.h deleted file mode 100644 index a5f08a41a..000000000 --- a/src/sp-filter-fns.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef SEEN_SP_FILTER_FNS_H -#define SEEN_SP_FILTER_FNS_H - -/** \file - * Macros and fn declarations related to filters. - */ - -#include <glib/gtypes.h> -#include <glib-object.h> -#include "libnr/nr-forward.h" -#include "sp-filter-units.h" -#include "sp-filter-primitive.h" - -class SPFilter; - -namespace Inkscape { -namespace XML { -class Node; -} -} - -#define SP_TYPE_FILTER (sp_filter_get_type()) -#define SP_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FILTER, SPFilter)) -#define SP_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FILTER, SPFilterClass)) -#define SP_IS_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FILTER)) -#define SP_IS_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FILTER)) - -#define SP_FILTER_FILTER_UNITS(f) (SP_FILTER(f)->filterUnits) -#define SP_FILTER_PRIMITIVE_UNITS(f) (SP_FILTER(f)->primitiveUnits) - -GType sp_filter_get_type(); - -//need to define function -void sp_filter_set_filter_units(SPFilter *filter, SPFilterUnits filterUnits); -//need to define function -void sp_filter_set_primitive_units(SPFilter *filter, SPFilterUnits filterUnits); - -SPFilterPrimitive *add_primitive(SPFilter *filter, SPFilterPrimitive *primitive); -SPFilterPrimitive *get_primitive(SPFilter *filter, int index); - - -#endif /* !SEEN_SP_FILTER_FNS_H */ - -/* - 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 : diff --git a/src/sp-filter-primitive.h b/src/sp-filter-primitive.h index 8922ac20a..60104047e 100644 --- a/src/sp-filter-primitive.h +++ b/src/sp-filter-primitive.h @@ -15,9 +15,7 @@ */ #include "sp-object.h" -#include "display/nr-filter.h" -#include "display/nr-filter-primitive.h" -#include "display/nr-filter-types.h" +#include "svg/svg-length.h" #define SP_TYPE_FILTER_PRIMITIVE (sp_filter_primitive_get_type ()) #define SP_FILTER_PRIMITIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_FILTER_PRIMITIVE, SPFilterPrimitive)) @@ -27,6 +25,12 @@ class SPFilterPrimitive; class SPFilterPrimitiveClass; +namespace Inkscape { +namespace Filters { +class Filter; +class FilterPrimitive; +} } + struct SPFilterPrimitive : public SPObject { int image_in, image_out; diff --git a/src/sp-filter-reference.cpp b/src/sp-filter-reference.cpp index 41db865fc..57600ad39 100644 --- a/src/sp-filter-reference.cpp +++ b/src/sp-filter-reference.cpp @@ -1,3 +1,4 @@ +#include "sp-filter.h" #include "sp-filter-reference.h" bool diff --git a/src/sp-filter-reference.h b/src/sp-filter-reference.h index 2e1d4648e..168ec1c1d 100644 --- a/src/sp-filter-reference.h +++ b/src/sp-filter-reference.h @@ -2,8 +2,10 @@ #define SEEN_SP_FILTER_REFERENCE_H #include "uri-references.h" -#include "sp-filter-fns.h" + class SPObject; +class SPDocument; +class SPFilter; class SPFilterReference : public Inkscape::URIReference { public: @@ -18,7 +20,6 @@ protected: virtual bool _acceptObject(SPObject *obj) const; }; - #endif /* !SEEN_SP_FILTER_REFERENCE_H */ /* diff --git a/src/sp-filter.cpp b/src/sp-filter.cpp index fd4319320..a7c1aa1fb 100644 --- a/src/sp-filter.cpp +++ b/src/sp-filter.cpp @@ -28,6 +28,7 @@ using std::pair; #include "document.h" #include "sp-filter.h" #include "sp-filter-reference.h" +#include "sp-filter-primitive.h" #include "uri.h" #include "xml/repr.h" #include <cstring> diff --git a/src/sp-filter.h b/src/sp-filter.h index 45586f1fb..4ba04ecf0 100644 --- a/src/sp-filter.h +++ b/src/sp-filter.h @@ -1,10 +1,6 @@ -#ifndef SP_FILTER_H_SEEN -#define SP_FILTER_H_SEEN - /** \file - * SVG <filter> implementation, see sp-filter.cpp. - */ -/* + * SVG <filter> element + *//* * Authors: * Hugo Rodrigues <haa.rodrigues@gmail.com> * Niko Kiirala <niko@kiirala.com> @@ -13,6 +9,8 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifndef SP_FILTER_H_SEEN +#define SP_FILTER_H_SEEN #include <map> @@ -21,18 +19,24 @@ #include "number-opt-number.h" #include "sp-object.h" #include "sp-filter-units.h" -#include "sp-filter-fns.h" #include "svg/svg-length.h" -#include "display/nr-filter.h" -/* Filter base class */ +#define SP_TYPE_FILTER (sp_filter_get_type()) +#define SP_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FILTER, SPFilter)) +#define SP_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FILTER, SPFilterClass)) +#define SP_IS_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FILTER)) +#define SP_IS_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FILTER)) -/* MACROS DEFINED IN FILE sp-filter-fns.h */ +#define SP_FILTER_FILTER_UNITS(f) (SP_FILTER(f)->filterUnits) +#define SP_FILTER_PRIMITIVE_UNITS(f) (SP_FILTER(f)->primitiveUnits) -struct SPFilterReference; +namespace Inkscape { +namespace Filters { +class Filter; +} } -class SPFilter; -class SPFilterClass; +struct SPFilterReference; +class SPFilterPrimitive; struct ltstr { bool operator()(const char* s1, const char* s2) const; @@ -70,34 +74,31 @@ struct SPFilterClass { SPObjectClass parent_class; }; -/* - * Initializes the given Inkscape::Filters::Filter object as a renderer for this - * SPFilter object. - */ +GType sp_filter_get_type(); + +void sp_filter_set_filter_units(SPFilter *filter, SPFilterUnits filterUnits); +void sp_filter_set_primitive_units(SPFilter *filter, SPFilterUnits filterUnits); +SPFilterPrimitive *add_primitive(SPFilter *filter, SPFilterPrimitive *primitive); +SPFilterPrimitive *get_primitive(SPFilter *filter, int index); + +/* Initializes the given Inkscape::Filters::Filter object as a renderer for this + * SPFilter object. */ void sp_filter_build_renderer(SPFilter *sp_filter, Inkscape::Filters::Filter *nr_filter); -/* - * Returns the number of filter primitives in this SPFilter object. - */ +/// Returns the number of filter primitives in this SPFilter object. int sp_filter_primitive_count(SPFilter *filter); -/** - * Returns a slot number for given image name, or -1 for unknown name. - */ +/// Returns a slot number for given image name, or -1 for unknown name. int sp_filter_get_image_name(SPFilter *filter, gchar const *name); -/** - * Returns slot number for given image name, even if it's unknown. - */ + +/// Returns slot number for given image name, even if it's unknown. int sp_filter_set_image_name(SPFilter *filter, gchar const *name); -/** - * Finds image name based on it's slot number. Returns 0 for unknown slot - * numbers. - */ + +/** Finds image name based on it's slot number. Returns 0 for unknown slot + * numbers. */ gchar const *sp_filter_name_for_image(SPFilter const *filter, int const image); -/* - * Returns a result image name that is not in use inside this filter. - */ +/// Returns a result image name that is not in use inside this filter. Glib::ustring sp_filter_get_new_result_name(SPFilter *filter); #endif /* !SP_FILTER_H_SEEN */ diff --git a/src/sp-flowdiv.cpp b/src/sp-flowdiv.cpp index 4dfdcbb9a..5cb258735 100644 --- a/src/sp-flowdiv.cpp +++ b/src/sp-flowdiv.cpp @@ -5,7 +5,6 @@ # include "config.h" #endif -#include "libnr/nr-matrix-ops.h" #include "xml/repr.h" //#include "svg/svg.h" diff --git a/src/sp-gaussian-blur.h b/src/sp-gaussian-blur.h deleted file mode 100644 index 9b6b9aa9b..000000000 --- a/src/sp-gaussian-blur.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef SP_GAUSSIANBLUR_H_SEEN -#define SP_GAUSSIANBLUR_H_SEEN - -/** \file - * SVG <gaussianBlur> implementation, see sp-gaussianBlur.cpp. - */ -/* - * Authors: - * Hugo Rodrigues <haa.rodrigues@gmail.com> - * - * Copyright (C) 2006 Hugo Rodrigues - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "sp-filter.h" -#include "sp-gaussian-blur-fns.h" - -/* GaussianBlur base class */ -class SPGaussianBlurClass; - -struct SPGaussianBlur : public SPFilterPrimitive { - /** stdDeviation attribute */ - NumberOptNumber stdDeviation; -}; - -struct SPGaussianBlurClass { - SPFilterPrimitiveClass parent_class; -}; - -GType sp_gaussianBlur_get_type(); - - -#endif /* !SP_GAUSSIANBLUR_H_SEEN */ - -/* - 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 : diff --git a/src/sp-gradient-fns.h b/src/sp-gradient-fns.h index be2caf5b0..5fb939905 100644 --- a/src/sp-gradient-fns.h +++ b/src/sp-gradient-fns.h @@ -19,8 +19,7 @@ SPGradientSpread sp_gradient_get_spread (SPGradient *gradient); void sp_gradient_repr_write_vector(SPGradient *gr); void sp_gradient_repr_clear_vector(SPGradient *gr); -void sp_gradient_render_vector_block_rgba(SPGradient *gr, guchar *px, gint w, gint h, gint rs, gint pos, gint span, bool horizontal); -void sp_gradient_render_vector_block_rgb(SPGradient *gr, guchar *px, gint w, gint h, gint rs, gint pos, gint span, bool horizontal); +cairo_pattern_t *sp_gradient_create_preview_pattern(SPGradient *gradient, double width); /** Transforms to/from gradient position space in given environment */ Geom::Affine sp_gradient_get_g2d_matrix(SPGradient const *gr, Geom::Affine const &ctm, diff --git a/src/sp-gradient.cpp b/src/sp-gradient.cpp index 82d62547a..3aa14dc45 100644 --- a/src/sp-gradient.cpp +++ b/src/sp-gradient.cpp @@ -23,16 +23,12 @@ #include <cstring> #include <string> -#include <libnr/nr-matrix-fns.h> -#include <libnr/nr-matrix-ops.h> -#include <libnr/nr-matrix-scale-ops.h> #include <2geom/transforms.h> #include <sigc++/functors/ptr_fun.h> #include <sigc++/adaptors/bind.h> -#include "libnr/nr-gradient.h" -#include "libnr/nr-pixops.h" +#include "display/cairo-utils.h" #include "svg/svg.h" #include "svg/svg-color.h" #include "svg/css-ostringstream.h" @@ -360,7 +356,7 @@ void SPGradientImpl::classInit(SPGradientClass *klass) { SPObjectClass *sp_object_class = (SPObjectClass *) klass; - gradient_parent_class = SP_PAINT_SERVER_CLASS( g_type_class_ref(SP_TYPE_PAINT_SERVER) ); + gradient_parent_class = (SPPaintServerClass *)g_type_class_ref(SP_TYPE_PAINT_SERVER); sp_object_class->build = SPGradientImpl::build; sp_object_class->release = SPGradientImpl::release; @@ -399,8 +395,6 @@ void SPGradientImpl::init(SPGradient *gr) gr->vector.built = false; gr->vector.stops.clear(); - gr->color = NULL; - new (&gr->modified_connection) sigc::connection(); } @@ -460,11 +454,6 @@ void SPGradientImpl::release(SPObject *object) gradient->ref = NULL; } - if (gradient->color) { - g_free(gradient->color); - gradient->color = NULL; - } - gradient->modified_connection.~connection(); if (((SPObjectClass *) gradient_parent_class)->release) @@ -662,7 +651,7 @@ void SPGradientImpl::modified(SPObject *object, guint flags) } if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { - gr->ensureColors(); + gr->ensureVector(); } if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; @@ -1006,12 +995,6 @@ bool SPGradient::invalidateVector() { bool ret = false; - if (color != NULL) { - g_free(color); - color = NULL; - ret = true; - } - if (vector.built) { vector.built = false; vector.stops.clear(); @@ -1119,303 +1102,6 @@ void SPGradient::rebuildVector() vector.built = true; } -/** - * The gradient's color array is newly created and set up from vector. - * Also, the gradient's color_grayscale is created. - */ -void SPGradient::ensureColors() -{ - if (!vector.built) { - rebuildVector(); - } - g_return_if_fail(!vector.stops.empty()); - - /// \todo Where is the memory freed? - if (!color) { - color = g_new(guchar, 4 * NCOLORS); - } - if (!color_grayscale) { - color_grayscale = g_new(guchar, 4 * NCOLORS); - } - - // This assumes that vector is a zero-order B-spline (box function) approximation of the "true" gradient. - // This means that the "true" gradient must be prefiltered using a zero order B-spline and then sampled. - // Furthermore, the first element corresponds to offset="0" and the last element to offset="1". - - double remainder[4] = {0,0,0,0}; - double remainder_for_end[4] = {0,0,0,0}; // Used at the end - switch(spread) { - case SP_GRADIENT_SPREAD_PAD: - remainder[0] = 0.5*vector.stops[0].color.v.c[0]; // Half of the first cell uses the color of the first stop - remainder[1] = 0.5*vector.stops[0].color.v.c[1]; - remainder[2] = 0.5*vector.stops[0].color.v.c[2]; - remainder[3] = 0.5*vector.stops[0].opacity; - remainder_for_end[0] = 0.5*vector.stops[vector.stops.size() - 1].color.v.c[0]; // Half of the first cell uses the color of the last stop - remainder_for_end[1] = 0.5*vector.stops[vector.stops.size() - 1].color.v.c[1]; - remainder_for_end[2] = 0.5*vector.stops[vector.stops.size() - 1].color.v.c[2]; - remainder_for_end[3] = 0.5*vector.stops[vector.stops.size() - 1].opacity; - break; - case SP_GRADIENT_SPREAD_REFLECT: - case SP_GRADIENT_SPREAD_REPEAT: - // These two are handled differently, see below. - break; - default: - g_error("Spread type not supported!"); - }; - for (unsigned int i = 0; i < vector.stops.size() - 1; i++) { - double r0 = vector.stops[i].color.v.c[0]; - double g0 = vector.stops[i].color.v.c[1]; - double b0 = vector.stops[i].color.v.c[2]; - double a0 = vector.stops[i].opacity; - double r1 = vector.stops[i+1].color.v.c[0]; - double g1 = vector.stops[i+1].color.v.c[1]; - double b1 = vector.stops[i+1].color.v.c[2]; - double a1 = vector.stops[i+1].opacity; - double o0 = vector.stops[i].offset * (NCOLORS-1); - double o1 = vector.stops[i + 1].offset * (NCOLORS-1); - unsigned int ob = (unsigned int) floor(o0+.5); // These are the first and last element that might be affected by this interval. - unsigned int oe = (unsigned int) floor(o1+.5); // These need to be computed the same to ensure that ob will be covered by the next interval if oe==ob - - if (oe == ob) { - // Simple case, this interval starts and stops within one cell - // The contribution of this interval is: - // (o1-o0)*(c(o0)+c(o1))/2 - // = (o1-o0)*(c0+c1)/2 - double dt = 0.5*(o1-o0); - remainder[0] += dt*(r0 + r1); - remainder[1] += dt*(g0 + g1); - remainder[2] += dt*(b0 + b1); - remainder[3] += dt*(a0 + a1); - } else { - // First compute colors for the cells which are fully covered by the current interval. - // The prefiltered values are equal to the midpoint of each cell here. - // f = (j-o0)/(o1-o0) - // = j*(1/(o1-o0)) - o0/(o1-o0) - double f = (ob-o0) / (o1-o0); - double df = 1. / (o1-o0); - for (unsigned int j = ob+1; j < oe; j++) { - f += df; - color[4 * j + 0] = (unsigned char) floor(255*(r0 + f*(r1-r0)) + .5); - color[4 * j + 1] = (unsigned char) floor(255*(g0 + f*(g1-g0)) + .5); - color[4 * j + 2] = (unsigned char) floor(255*(b0 + f*(b1-b0)) + .5); - color[4 * j + 3] = (unsigned char) floor(255*(a0 + f*(a1-a0)) + .5); - } - - // Now handle the beginning - // The contribution of the last point is already in remainder. - // The contribution of this point is: - // (ob+.5-o0)*(c(o0)+c(ob+.5))/2 - // = (ob+.5-o0)*c((o0+ob+.5)/2) - // = (ob+.5-o0)*(c0+((o0+ob+.5)/2-o0)*df*(c1-c0)) - // = (ob+.5-o0)*(c0+(ob+.5-o0)*df*(c1-c0)/2) - double dt = ob+.5-o0; - f = 0.5*dt*df; - if (ob==0 && spread==SP_GRADIENT_SPREAD_REFLECT) { - // The first half of the first cell is just a mirror image of the second half, so simply multiply it by 2. - color[4 * ob + 0] = (unsigned char) floor(2*255*(remainder[0] + dt*(r0 + f*(r1-r0))) + .5); - color[4 * ob + 1] = (unsigned char) floor(2*255*(remainder[1] + dt*(g0 + f*(g1-g0))) + .5); - color[4 * ob + 2] = (unsigned char) floor(2*255*(remainder[2] + dt*(b0 + f*(b1-b0))) + .5); - color[4 * ob + 3] = (unsigned char) floor(2*255*(remainder[3] + dt*(a0 + f*(a1-a0))) + .5); - } else if (ob==0 && spread==SP_GRADIENT_SPREAD_REPEAT) { - // The first cell is the same as the last cell, so save whatever is in the second half here and deal with the rest later. - remainder_for_end[0] = remainder[0] + dt*(r0 + f*(r1-r0)); - remainder_for_end[1] = remainder[1] + dt*(g0 + f*(g1-g0)); - remainder_for_end[2] = remainder[2] + dt*(b0 + f*(b1-b0)); - remainder_for_end[3] = remainder[3] + dt*(a0 + f*(a1-a0)); - } else { - // The first half of the cell was already in remainder. - color[4 * ob + 0] = (unsigned char) floor(255*(remainder[0] + dt*(r0 + f*(r1-r0))) + .5); - color[4 * ob + 1] = (unsigned char) floor(255*(remainder[1] + dt*(g0 + f*(g1-g0))) + .5); - color[4 * ob + 2] = (unsigned char) floor(255*(remainder[2] + dt*(b0 + f*(b1-b0))) + .5); - color[4 * ob + 3] = (unsigned char) floor(255*(remainder[3] + dt*(a0 + f*(a1-a0))) + .5); - } - - // Now handle the end, which should end up in remainder - // The contribution of this point is: - // (o1-oe+.5)*(c(o1)+c(oe-.5))/2 - // = (o1-oe+.5)*c((o1+oe-.5)/2) - // = (o1-oe+.5)*(c0+((o1+oe-.5)/2-o0)*df*(c1-c0)) - dt = o1-oe+.5; - f = (0.5*(o1+oe-.5)-o0)*df; - remainder[0] = dt*(r0 + f*(r1-r0)); - remainder[1] = dt*(g0 + f*(g1-g0)); - remainder[2] = dt*(b0 + f*(b1-b0)); - remainder[3] = dt*(a0 + f*(a1-a0)); - } - } - switch(spread) { - case SP_GRADIENT_SPREAD_PAD: - color[4 * (NCOLORS-1) + 0] = (unsigned char) floor(255*(remainder[0]+remainder_for_end[0]) + .5); - color[4 * (NCOLORS-1) + 1] = (unsigned char) floor(255*(remainder[1]+remainder_for_end[1]) + .5); - color[4 * (NCOLORS-1) + 2] = (unsigned char) floor(255*(remainder[2]+remainder_for_end[2]) + .5); - color[4 * (NCOLORS-1) + 3] = (unsigned char) floor(255*(remainder[3]+remainder_for_end[3]) + .5); - break; - case SP_GRADIENT_SPREAD_REFLECT: - // The second half is the same as the first half, so multiply by 2. - color[4 * (NCOLORS-1) + 0] = (unsigned char) floor(2*255*remainder[0] + .5); - color[4 * (NCOLORS-1) + 1] = (unsigned char) floor(2*255*remainder[1] + .5); - color[4 * (NCOLORS-1) + 2] = (unsigned char) floor(2*255*remainder[2] + .5); - color[4 * (NCOLORS-1) + 3] = (unsigned char) floor(2*255*remainder[3] + .5); - break; - case SP_GRADIENT_SPREAD_REPEAT: - // The second half is the same as the second half of the first cell (which was saved in remainder_for_end). - color[0] = color[4 * (NCOLORS-1) + 0] = (unsigned char) floor(255*(remainder[0]+remainder_for_end[0]) + .5); - color[1] = color[4 * (NCOLORS-1) + 1] = (unsigned char) floor(255*(remainder[1]+remainder_for_end[1]) + .5); - color[2] = color[4 * (NCOLORS-1) + 2] = (unsigned char) floor(255*(remainder[2]+remainder_for_end[2]) + .5); - color[3] = color[4 * (NCOLORS-1) + 3] = (unsigned char) floor(255*(remainder[3]+remainder_for_end[3]) + .5); - break; - } - - // Fill color_grayscale array - for (unsigned j = 0; j < NCOLORS; j++) { - guint32 rgba = Grayscale::process(color[4 * j + 0], color[4 * j + 1], color[4 * j + 2], color[4 * j + 3]); - color_grayscale[4 * j + 0] = SP_RGBA32_R_U(rgba); - color_grayscale[4 * j + 1] = SP_RGBA32_G_U(rgba); - color_grayscale[4 * j + 2] = SP_RGBA32_B_U(rgba); - color_grayscale[4 * j + 3] = SP_RGBA32_A_U(rgba); - } -} - -/** - * Renders gradient vector to buffer as line. - * - * RGB buffer background should be set up beforehand. - * - * @param len,width,height,rowstride Buffer parameters (1 or 2 dimensional). - * @param span Full integer width of requested gradient. - * @param pos Buffer starting position in span. - */ -static void -sp_gradient_render_vector_line_rgba(SPGradient *const gradient, guchar *buf, - gint const len, gint const pos, gint const span) -{ - g_return_if_fail(gradient != NULL); - g_return_if_fail(SP_IS_GRADIENT(gradient)); - g_return_if_fail(buf != NULL); - g_return_if_fail(len > 0); - g_return_if_fail(pos >= 0); - g_return_if_fail(pos + len <= span); - g_return_if_fail(span > 0); - - if (!gradient->color) { - gradient->ensureColors(); - } - - gint idx = (pos * 1024 << 8) / span; - gint didx = (1024 << 8) / span; - - bool grayscale = false; // this rendering is for UI items, like the gradient edit dialog - if (grayscale) { - for (gint x = 0; x < len; x++) { - guchar luminance = Grayscale::luminance( gradient->color[4 * (idx >> 8)], gradient->color[4 * (idx >> 8) + 1], gradient->color[4 * (idx >> 8) + 2] ); - *buf++ = luminance; - *buf++ = luminance; - *buf++ = luminance; - *buf++ = gradient->color[4 * (idx >> 8) + 3]; - idx += didx; - } - } else { - for (gint x = 0; x < len; x++) { - /// \todo Can this be done with 4 byte copies? - *buf++ = gradient->color[4 * (idx >> 8)]; - *buf++ = gradient->color[4 * (idx >> 8) + 1]; - *buf++ = gradient->color[4 * (idx >> 8) + 2]; - *buf++ = gradient->color[4 * (idx >> 8) + 3]; - idx += didx; - } - } -} - -/** - * Render rectangular RGBA area from gradient vector. - */ -void -sp_gradient_render_vector_block_rgba(SPGradient *const gradient, guchar *buf, - gint const width, gint const height, gint const rowstride, - gint const pos, gint const span, bool const horizontal) -{ - g_return_if_fail(gradient != NULL); - g_return_if_fail(SP_IS_GRADIENT(gradient)); - g_return_if_fail(buf != NULL); - g_return_if_fail(width > 0); - g_return_if_fail(height > 0); - g_return_if_fail(pos >= 0); - g_return_if_fail((horizontal && (pos + width <= span)) || (!horizontal && (pos + height <= span))); - g_return_if_fail(span > 0); - - if (horizontal) { - sp_gradient_render_vector_line_rgba(gradient, buf, width, pos, span); - for (gint y = 1; y < height; y++) { - memcpy(buf + y * rowstride, buf, 4 * width); - } - } else { - guchar *tmp = (guchar *)alloca(4 * height); - sp_gradient_render_vector_line_rgba(gradient, tmp, height, pos, span); - for (gint y = 0; y < height; y++) { - guchar *b = buf + y * rowstride; - for (gint x = 0; x < width; x++) { - *b++ = tmp[0]; - *b++ = tmp[1]; - *b++ = tmp[2]; - *b++ = tmp[3]; - } - tmp += 4; - } - } -} - -/** - * Render rectangular RGB area from gradient vector. - */ -void -sp_gradient_render_vector_block_rgb(SPGradient *gradient, guchar *buf, - gint const width, gint const height, gint const /*rowstride*/, - gint const pos, gint const span, bool const horizontal) -{ - g_return_if_fail(gradient != NULL); - g_return_if_fail(SP_IS_GRADIENT(gradient)); - g_return_if_fail(buf != NULL); - g_return_if_fail(width > 0); - g_return_if_fail(height > 0); - g_return_if_fail(pos >= 0); - g_return_if_fail((horizontal && (pos + width <= span)) || (!horizontal && (pos + height <= span))); - g_return_if_fail(span > 0); - - if (horizontal) { - guchar *tmp = (guchar*)alloca(4 * width); - sp_gradient_render_vector_line_rgba(gradient, tmp, width, pos, span); - for (gint y = 0; y < height; y++) { - guchar *t = tmp; - for (gint x = 0; x < width; x++) { - gint a = t[3]; - gint fc = (t[0] - buf[0]) * a; - buf[0] = buf[0] + ((fc + (fc >> 8) + 0x80) >> 8); - fc = (t[1] - buf[1]) * a; - buf[1] = buf[1] + ((fc + (fc >> 8) + 0x80) >> 8); - fc = (t[2] - buf[2]) * a; - buf[2] = buf[2] + ((fc + (fc >> 8) + 0x80) >> 8); - buf += 3; - t += 4; - } - } - } else { - guchar *tmp = (guchar*)alloca(4 * height); - sp_gradient_render_vector_line_rgba(gradient, tmp, height, pos, span); - for (gint y = 0; y < height; y++) { - guchar *t = tmp + 4 * y; - for (gint x = 0; x < width; x++) { - gint a = t[3]; - gint fc = (t[0] - buf[0]) * a; - buf[0] = buf[0] + ((fc + (fc >> 8) + 0x80) >> 8); - fc = (t[1] - buf[1]) * a; - buf[1] = buf[1] + ((fc + (fc >> 8) + 0x80) >> 8); - fc = (t[2] - buf[2]) * a; - buf[2] = buf[2] + ((fc + (fc >> 8) + 0x80) >> 8); - } - } - } -} - Geom::Affine sp_gradient_get_g2d_matrix(SPGradient const *gr, Geom::Affine const &ctm, Geom::Rect const &bbox) { @@ -1460,21 +1146,6 @@ sp_gradient_set_gs2d_matrix(SPGradient *gr, Geom::Affine const &ctm, * Linear Gradient */ -class SPLGPainter; - -/// A context with linear gradient, painter, and gradient renderer. -struct SPLGPainter { - SPPainter painter; - SPLinearGradient *lg; - - NRLGradientRenderer lgr; - - static SPPainter * painter_new(SPPaintServer *ps, - Geom::Affine const &full_transform, - Geom::Affine const &parent_transform, - NRRect const *bbox); -}; - static void sp_lineargradient_class_init(SPLinearGradientClass *klass); static void sp_lineargradient_init(SPLinearGradient *lg); @@ -1484,10 +1155,7 @@ static void sp_lineargradient_build(SPObject *object, static void sp_lineargradient_set(SPObject *object, unsigned key, gchar const *value); static Inkscape::XML::Node *sp_lineargradient_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -static void sp_lineargradient_painter_free(SPPaintServer *ps, SPPainter *painter); - -static void sp_lg_fill(SPPainter *painter, NRPixBlock *pb); +static cairo_pattern_t *sp_lineargradient_create_pattern(SPPaintServer *ps, cairo_t *ct, NRRect const *bbox, double opacity); static SPGradientClass *lg_parent_class; @@ -1520,7 +1188,7 @@ sp_lineargradient_get_type() static void sp_lineargradient_class_init(SPLinearGradientClass *klass) { SPObjectClass *sp_object_class = (SPObjectClass *) klass; - SPPaintServerClass *ps_class = SP_PAINT_SERVER_CLASS( klass ); + SPPaintServerClass *ps_class = (SPPaintServerClass *) klass; lg_parent_class = (SPGradientClass*)g_type_class_ref(SP_TYPE_GRADIENT); @@ -1528,8 +1196,7 @@ static void sp_lineargradient_class_init(SPLinearGradientClass *klass) sp_object_class->set = sp_lineargradient_set; sp_object_class->write = sp_lineargradient_write; - ps_class->painter_new = SPLGPainter::painter_new; - ps_class->painter_free = sp_lineargradient_painter_free; + ps_class->pattern_new = sp_lineargradient_create_pattern; } /** @@ -1619,86 +1286,6 @@ sp_lineargradient_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inks } /** - * Create linear gradient context. - * - * Basically we have to deal with transformations - * - * 1) color2norm - maps point in (0,NCOLORS) vector to (0,1) vector - * 2) norm2pos - maps (0,1) vector to x1,y1 - x2,y2 - * 2) gradientTransform - * 3) bbox2user - * 4) ctm == userspace to pixel grid - * - * See also (*) in sp-pattern about why we may need parent_transform. - * - * \todo (point 1 above) fixme: I do not know how to deal with start > 0 - * and end < 1. - */ -SPPainter * SPLGPainter::painter_new(SPPaintServer *ps, - Geom::Affine const &full_transform, - Geom::Affine const &/*parent_transform*/, - NRRect const *bbox) -{ - SPLinearGradient *lg = SP_LINEARGRADIENT(ps); - SPGradient *gr = SP_GRADIENT(ps); - - if (!gr->color) { - gr->ensureColors(); - } - - SPLGPainter *lgp = g_new(SPLGPainter, 1); - - lgp->painter.server_type = G_OBJECT_TYPE(ps); - lgp->painter.fill = sp_lg_fill; - - lgp->lg = lg; - - /** \todo - * Technically speaking, we map NCOLORS on line [start,end] onto line - * [0,1]. I almost think we should fill color array start and end in - * that case. The alternative would be to leave these just empty garbage - * or something similar. Originally I had 1023.9999 here - not sure - * whether we have really to cut out ceil int (Lauris). - */ - Geom::Affine color2norm(Geom::identity()); - Geom::Affine color2px; - if (gr->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) { - Geom::Affine norm2pos(Geom::identity()); - - /* BBox to user coordinate system */ - Geom::Affine bbox2user(bbox->x1 - bbox->x0, 0, 0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0); - - Geom::Affine color2pos = color2norm * norm2pos; - Geom::Affine color2tpos = color2pos * gr->gradientTransform; - Geom::Affine color2user = color2tpos * bbox2user; - color2px = color2user * full_transform; - - } else { - /* Problem: What to do, if we have mixed lengths and percentages? */ - /* Currently we do ignore percentages at all, but that is not good (lauris) */ - - Geom::Affine norm2pos(Geom::identity()); - Geom::Affine color2pos = color2norm * norm2pos; - Geom::Affine color2tpos = color2pos * gr->gradientTransform; - color2px = color2tpos * full_transform; - - } - // TODO: remove color2px_nr after converting to 2geom - NR::Matrix color2px_nr = from_2geom(color2px); - nr_lgradient_renderer_setup(&lgp->lgr, gr->color, gr->fetchSpread(), &color2px_nr, - lg->x1.computed, lg->y1.computed, - lg->x2.computed, lg->y2.computed); - - return (SPPainter *) lgp; -} - -static void -sp_lineargradient_painter_free(SPPaintServer */*ps*/, SPPainter *painter) -{ - g_free(painter); -} - -/** * Directly set properties of linear gradient and request modified. */ void @@ -1718,45 +1305,10 @@ sp_lineargradient_set_position(SPLinearGradient *lg, lg->requestModified(SP_OBJECT_MODIFIED_FLAG); } -/** - * Callback when linear gradient object is rendered. - */ -static void -sp_lg_fill(SPPainter *painter, NRPixBlock *pb) -{ - SPLGPainter *lgp = (SPLGPainter *) painter; - - if (lgp->lg->color == NULL) { - lgp->lg->ensureColors(); - } - bool grayscale = Grayscale::activeDesktopIsGrayscale(); // TODO: find good way to access the current rendermode - if (grayscale) { - lgp->lgr.vector = lgp->lg->color_grayscale; - } else { - lgp->lgr.vector = lgp->lg->color; - } - - nr_render((NRRenderer *) &lgp->lgr, pb, NULL); -} - /* * Radial Gradient */ -class SPRGPainter; - -/// A context with radial gradient, painter, and gradient renderer. -struct SPRGPainter { - SPPainter painter; - SPRadialGradient *rg; - NRRGradientRenderer rgr; - - static SPPainter *painter_new(SPPaintServer *ps, - Geom::Affine const &full_transform, - Geom::Affine const &parent_transform, - NRRect const *bbox); -}; - static void sp_radialgradient_class_init(SPRadialGradientClass *klass); static void sp_radialgradient_init(SPRadialGradient *rg); @@ -1766,9 +1318,7 @@ static void sp_radialgradient_build(SPObject *object, static void sp_radialgradient_set(SPObject *object, unsigned key, gchar const *value); static Inkscape::XML::Node *sp_radialgradient_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_radialgradient_painter_free(SPPaintServer *ps, SPPainter *painter); - -static void sp_rg_fill(SPPainter *painter, NRPixBlock *pb); +static cairo_pattern_t *sp_radialgradient_create_pattern(SPPaintServer *ps, cairo_t *ct, NRRect const *bbox, double opacity); static SPGradientClass *rg_parent_class; @@ -1801,7 +1351,7 @@ sp_radialgradient_get_type() static void sp_radialgradient_class_init(SPRadialGradientClass *klass) { SPObjectClass *sp_object_class = (SPObjectClass *) klass; - SPPaintServerClass *ps_class = SP_PAINT_SERVER_CLASS( klass ); + SPPaintServerClass *ps_class = (SPPaintServerClass *) klass; rg_parent_class = (SPGradientClass*)g_type_class_ref(SP_TYPE_GRADIENT); @@ -1809,8 +1359,7 @@ static void sp_radialgradient_class_init(SPRadialGradientClass *klass) sp_object_class->set = sp_radialgradient_set; sp_object_class->write = sp_radialgradient_write; - ps_class->painter_new = SPRGPainter::painter_new; - ps_class->painter_free = sp_radialgradient_painter_free; + ps_class->pattern_new = sp_radialgradient_create_pattern; } /** @@ -1921,68 +1470,6 @@ sp_radialgradient_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inks } /** - * Create radial gradient context. - */ -SPPainter *SPRGPainter::painter_new(SPPaintServer *ps, - Geom::Affine const &full_transform, - Geom::Affine const &/*parent_transform*/, - NRRect const *bbox) -{ - SPRadialGradient *rg = SP_RADIALGRADIENT(ps); - SPGradient *gr = SP_GRADIENT(ps); - - if (!gr->color) { - gr->ensureColors(); - } - - SPRGPainter *rgp = g_new(SPRGPainter, 1); - - rgp->painter.server_type = G_OBJECT_TYPE(ps); - rgp->painter.fill = sp_rg_fill; - - rgp->rg = rg; - - Geom::Affine gs2px; - - if (gr->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) { - /** \todo - * fixme: We may try to normalize here too, look at - * linearGradient (Lauris) - */ - - /* BBox to user coordinate system */ - Geom::Affine bbox2user(bbox->x1 - bbox->x0, 0, 0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0); - - Geom::Affine gs2user = gr->gradientTransform * bbox2user; - - gs2px = gs2user * full_transform; - } else { - /** \todo - * Problem: What to do, if we have mixed lengths and percentages? - * Currently we do ignore percentages at all, but that is not - * good (lauris) - */ - - gs2px = gr->gradientTransform * full_transform; - } - // TODO: remove gs2px_nr after converting to 2geom - NR::Matrix gs2px_nr = from_2geom(gs2px); - nr_rgradient_renderer_setup(&rgp->rgr, gr->color, gr->fetchSpread(), - &gs2px_nr, - rg->cx.computed, rg->cy.computed, - rg->fx.computed, rg->fy.computed, - rg->r.computed); - - return (SPPainter *) rgp; -} - -static void -sp_radialgradient_painter_free(SPPaintServer */*ps*/, SPPainter *painter) -{ - g_free(painter); -} - -/** * Directly set properties of radial gradient and request modified. */ void @@ -2002,25 +1489,101 @@ sp_radialgradient_set_position(SPRadialGradient *rg, rg->requestModified(SP_OBJECT_MODIFIED_FLAG); } -/** - * Callback when radial gradient object is rendered. - */ +/* CAIRO RENDERING STUFF */ + static void -sp_rg_fill(SPPainter *painter, NRPixBlock *pb) +sp_gradient_pattern_common_setup(cairo_pattern_t *cp, + SPGradient *gr, + NRRect const *bbox, + double opacity) { - SPRGPainter *rgp = (SPRGPainter *) painter; + // set spread type + switch (gr->getSpread()) { + case SP_GRADIENT_SPREAD_REFLECT: + cairo_pattern_set_extend(cp, CAIRO_EXTEND_REFLECT); + break; + case SP_GRADIENT_SPREAD_REPEAT: + cairo_pattern_set_extend(cp, CAIRO_EXTEND_REPEAT); + break; + case SP_GRADIENT_SPREAD_PAD: + default: + cairo_pattern_set_extend(cp, CAIRO_EXTEND_PAD); + break; + } - if (rgp->rg->color == NULL) { - rgp->rg->ensureColors(); + // add stops + for (std::vector<SPGradientStop>::iterator i = gr->vector.stops.begin(); + i != gr->vector.stops.end(); ++i) + { + // multiply stop opacity by paint opacity + cairo_pattern_add_color_stop_rgba(cp, i->offset, + i->color.v.c[0], i->color.v.c[1], i->color.v.c[2], i->opacity * opacity); } - bool grayscale = Grayscale::activeDesktopIsGrayscale(); // TODO: find good way to access the current rendermode - if (grayscale) { - rgp->rgr.vector = rgp->rg->color_grayscale; - } else { - rgp->rgr.vector = rgp->rg->color; + + // set pattern matrix + Geom::Affine gs2user = gr->gradientTransform; + if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) { + Geom::Affine bbox2user(bbox->x1 - bbox->x0, 0, 0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0); + gs2user *= bbox2user; + } + ink_cairo_pattern_set_matrix(cp, gs2user.inverse()); +} + +static cairo_pattern_t * +sp_radialgradient_create_pattern(SPPaintServer *ps, + cairo_t */* ct */, + NRRect const *bbox, + double opacity) +{ + SPRadialGradient *rg = SP_RADIALGRADIENT(ps); + SPGradient *gr = SP_GRADIENT(ps); + + gr->ensureVector(); + + cairo_pattern_t *cp = cairo_pattern_create_radial( + rg->fx.computed, rg->fy.computed, 0, + rg->cx.computed, rg->cy.computed, rg->r.computed); + + sp_gradient_pattern_common_setup(cp, gr, bbox, opacity); + + return cp; +} + +static cairo_pattern_t * +sp_lineargradient_create_pattern(SPPaintServer *ps, + cairo_t */* ct */, + NRRect const *bbox, + double opacity) +{ + SPLinearGradient *lg = SP_LINEARGRADIENT(ps); + SPGradient *gr = SP_GRADIENT(ps); + + gr->ensureVector(); + + cairo_pattern_t *cp = cairo_pattern_create_linear( + lg->x1.computed, lg->y1.computed, + lg->x2.computed, lg->y2.computed); + + sp_gradient_pattern_common_setup(cp, gr, bbox, opacity); + + return cp; +} + +cairo_pattern_t * +sp_gradient_create_preview_pattern(SPGradient *gr, double width) +{ + gr->ensureVector(); + + cairo_pattern_t *pat = cairo_pattern_create_linear(0, 0, width, 0); + + for (std::vector<SPGradientStop>::iterator i = gr->vector.stops.begin(); + i != gr->vector.stops.end(); ++i) + { + cairo_pattern_add_color_stop_rgba(pat, i->offset, + i->color.v.c[0], i->color.v.c[1], i->color.v.c[2], i->opacity); } - nr_render((NRRenderer *) &rgp->rgr, pb, NULL); + return pat; } /* diff --git a/src/sp-gradient.h b/src/sp-gradient.h index 217b9f3ee..85eb70e9b 100644 --- a/src/sp-gradient.h +++ b/src/sp-gradient.h @@ -19,7 +19,7 @@ #include <gdk/gdk.h> #include <glibmm/ustring.h> -#include "libnr/nr-matrix.h" +#include <2geom/affine.h> #include "sp-paint-server.h" #include "sp-gradient-spread.h" #include "sp-gradient-units.h" @@ -100,11 +100,6 @@ public: /** Composed vector */ SPGradientVector vector; - /** Rendered color array (4 * 1024 bytes) */ - guchar *color; - /** Rendered color array in grayscale (for grayscale viewmode) (4 * 1024 bytes) */ - guchar *color_grayscale; - sigc::connection modified_connection; bool hasStops() const; diff --git a/src/sp-image.cpp b/src/sp-image.cpp index 88daf31ba..f98a6c8e3 100644 --- a/src/sp-image.cpp +++ b/src/sp-image.cpp @@ -21,33 +21,26 @@ #include <png.h> #include <cstring> +#include <algorithm> #include <string> -#include <libnr/nr-matrix-fns.h> -#include <libnr/nr-matrix-ops.h> -#include <libnr/nr-translate-matrix-ops.h> -#include <libnr/nr-scale-translate-ops.h> -#include <libnr/nr-convert2geom.h> -#include <2geom/rect.h> -//#define GDK_PIXBUF_ENABLE_BACKEND 1 -//#include <gdk-pixbuf/gdk-pixbuf-io.h> -#include "display/nr-arena-image.h" -#include <display/curve.h> #include <glib/gstdio.h> +#include <2geom/rect.h> +#include <glibmm/i18n.h> +#include "display/nr-arena-image.h" +#include "display/cairo-utils.h" +#include "display/curve.h" //Added for preserveAspectRatio support -- EAF #include "enums.h" #include "attributes.h" - #include "print.h" #include "brokenimage.xpm" #include "document.h" #include "sp-image.h" #include "sp-clippath.h" -#include <glibmm/i18n.h> #include "xml/quote.h" -#include <xml/repr.h> +#include "xml/repr.h" #include "snap-candidate.h" -#include "libnr/nr-matrix-fns.h" #include "io/sys.h" #if ENABLE_LCMS @@ -96,6 +89,7 @@ static void sp_image_set_curve(SPImage *image); static GdkPixbuf *sp_image_repr_read_image( time_t& modTime, gchar*& pixPath, const gchar *href, const gchar *absref, const gchar *base ); static GdkPixbuf *sp_image_pixbuf_force_rgba (GdkPixbuf * pixbuf); +static void sp_image_update_arenaitem (SPImage *img, NRArenaImage *ai); static void sp_image_update_canvas_image (SPImage *image); static GdkPixbuf * sp_image_repr_read_dataURI (const gchar * uri_data); static GdkPixbuf * sp_image_repr_read_b64 (const gchar * uri_data); @@ -612,15 +606,9 @@ static void sp_image_init( SPImage *image ) image->width.unset(); image->height.unset(); image->aspect_align = SP_ASPECT_NONE; - - image->trimx = 0; - image->trimy = 0; - image->trimwidth = 0; - image->trimheight = 0; - image->viewx = 0; - image->viewy = 0; - image->viewwidth = 0; - image->viewheight = 0; + image->clipbox = Geom::Rect(); + image->sx = image->sy = 1.0; + image->ox = image->oy = 0.0; image->curve = NULL; @@ -924,16 +912,38 @@ static void sp_image_update( SPObject *object, SPCtx *ctx, unsigned int flags ) } #endif // ENABLE_LCMS image->pixbuf = pixbuf; + // convert to premultiplied native-endian ARGB for display with Cairo + convert_pixbuf_normal_to_argb32(image->pixbuf); } } } + + if (image->pixbuf) { + /* fixme: We are slightly violating spec here (Lauris) */ + if (!image->width._set) { + image->width.computed = gdk_pixbuf_get_width(image->pixbuf); + } + if (!image->height._set) { + image->height.computed = gdk_pixbuf_get_height(image->pixbuf); + } + } + + Geom::Point p(image->x.computed, image->y.computed); + Geom::Point wh(image->width.computed, image->height.computed); + image->clipbox = Geom::Rect(p, p + wh); + + image->ox = image->x.computed; + image->oy = image->y.computed; + + int pixwidth = gdk_pixbuf_get_width (image->pixbuf); + int pixheight = gdk_pixbuf_get_height (image->pixbuf); + + image->sx = image->width.computed / pixwidth; + image->sy = image->height.computed / pixheight; + // preserveAspectRatio calculate bounds / clipping rectangle -- EAF if (image->pixbuf && (image->aspect_align != SP_ASPECT_NONE)) { - int imagewidth, imageheight; - double x,y; - - imagewidth = gdk_pixbuf_get_width (image->pixbuf); - imageheight = gdk_pixbuf_get_height (image->pixbuf); + double x, y; switch (image->aspect_align) { case SP_ASPECT_XMIN_YMIN: @@ -979,43 +989,19 @@ static void sp_image_update( SPObject *object, SPCtx *ctx, unsigned int flags ) } if (image->aspect_clip == SP_ASPECT_SLICE) { - image->viewx = image->x.computed; - image->viewy = image->y.computed; - image->viewwidth = image->width.computed; - image->viewheight = image->height.computed; - if ((imagewidth*image->height.computed)>(image->width.computed*imageheight)) { - // Pixels aspect is wider than bounding box - image->trimheight = imageheight; - image->trimwidth = static_cast<int>(static_cast<double>(imageheight) * image->width.computed / image->height.computed); - image->trimy = 0; - image->trimx = static_cast<int>(static_cast<double>(imagewidth - image->trimwidth) * x); - } else { - // Pixels aspect is taller than bounding box - image->trimwidth = imagewidth; - image->trimheight = static_cast<int>(static_cast<double>(imagewidth) * image->height.computed / image->width.computed); - image->trimx = 0; - image->trimy = static_cast<int>(static_cast<double>(imageheight - image->trimheight) * y); - } + double scale = std::max(image->sx, image->sy); + image->sx = scale; + image->sy = scale; } else { - // Otherwise, assume SP_ASPECT_MEET - image->trimx = 0; - image->trimy = 0; - image->trimwidth = imagewidth; - image->trimheight = imageheight; - if ((imagewidth*image->height.computed)>(image->width.computed*imageheight)) { - // Pixels aspect is wider than bounding boz - image->viewwidth = image->width.computed; - image->viewheight = image->viewwidth * imageheight / imagewidth; - image->viewx=image->x.computed; - image->viewy=(image->height.computed - image->viewheight) * y + image->y.computed; - } else { - // Pixels aspect is taller than bounding box - image->viewheight = image->height.computed; - image->viewwidth = image->viewheight * imagewidth / imageheight; - image->viewy=image->y.computed; - image->viewx=(image->width.computed - image->viewwidth) * x + image->x.computed; - } + double scale = std::min(image->sx, image->sy); + image->sx = scale; + image->sy = scale; } + + double vw = pixwidth * image->sx; + double vh = pixheight * image->sy; + image->ox += x * (image->width.computed - vw); + image->oy += y * (image->height.computed - vh); } sp_image_update_canvas_image ((SPImage *) object); } @@ -1095,32 +1081,44 @@ static void sp_image_print( SPItem *item, SPPrintContext *ctx ) SPImage *image = SP_IMAGE(item); if (image->pixbuf && (image->width.computed > 0.0) && (image->height.computed > 0.0) ) { - guchar *px = gdk_pixbuf_get_pixels(image->pixbuf); - int w = gdk_pixbuf_get_width(image->pixbuf); - int h = gdk_pixbuf_get_height(image->pixbuf); - int rs = gdk_pixbuf_get_rowstride(image->pixbuf); - int pixskip = gdk_pixbuf_get_n_channels(image->pixbuf) * gdk_pixbuf_get_bits_per_sample(image->pixbuf) / 8; + GdkPixbuf *pb = gdk_pixbuf_copy(image->pixbuf); + convert_pixbuf_argb32_to_normal(pb); + + guchar *px = gdk_pixbuf_get_pixels(pb); + int w = gdk_pixbuf_get_width(pb); + int h = gdk_pixbuf_get_height(pb); + int rs = gdk_pixbuf_get_rowstride(pb); + int pixskip = gdk_pixbuf_get_n_channels(pb) * gdk_pixbuf_get_bits_per_sample(pb) / 8; - Geom::Affine t; if (image->aspect_align == SP_ASPECT_NONE) { - /* fixme: (Lauris) */ + Geom::Affine t; Geom::Translate tp(image->x.computed, image->y.computed); Geom::Scale s(image->width.computed, -image->height.computed); Geom::Translate ti(0.0, -1.0); t = s * tp; t = ti * t; + sp_print_image_R8G8B8A8_N(ctx, px, w, h, rs, &t, item->style); } else { // preserveAspectRatio - Geom::Translate tp(image->viewx, image->viewy); - Geom::Scale s(image->viewwidth, -image->viewheight); + double vw = image->width.computed / image->sx; + double vh = image->height.computed / image->sy; + + int trimwidth = std::min<int>(w, ceil(image->width.computed / vw * w)); + int trimheight = std::min<int>(h, ceil(image->height.computed / vh * h)); + int trimx = std::max<int>(0, floor((image->x.computed - image->ox) / vw * w)); + int trimy = std::max<int>(0, floor((image->y.computed - image->oy) / vh * h)); + + double vx = std::max<double>(image->ox, image->x.computed); + double vy = std::max<double>(image->oy, image->y.computed); + double vcw = std::min<double>(image->width.computed, vw); + double vch = std::min<double>(image->height.computed, vh); + + Geom::Affine t; + Geom::Translate tp(vx, vy); + Geom::Scale s(vcw, -vch); Geom::Translate ti(0.0, -1.0); t = s * tp; t = ti * t; - } - - if (image->aspect_align == SP_ASPECT_NONE) { - sp_print_image_R8G8B8A8_N(ctx, px, w, h, rs, &t, item->style); - } else { // preserveAspectRatio - sp_print_image_R8G8B8A8_N(ctx, px + image->trimx*pixskip + image->trimy*rs, image->trimwidth, image->trimheight, rs, &t, item->style); + sp_print_image_R8G8B8A8_N(ctx, px + trimx*pixskip + trimy*rs, trimwidth, trimheight, rs, &t, item->style); } } } @@ -1153,31 +1151,7 @@ static NRArenaItem *sp_image_show( SPItem *item, NRArena *arena, unsigned int /* SPImage * image = SP_IMAGE(item); NRArenaItem *ai = NRArenaImage::create(arena); - if (image->pixbuf) { - int pixskip = gdk_pixbuf_get_n_channels(image->pixbuf) * gdk_pixbuf_get_bits_per_sample(image->pixbuf) / 8; - int rs = gdk_pixbuf_get_rowstride(image->pixbuf); - nr_arena_image_set_style(NR_ARENA_IMAGE(ai), item->style); - if (image->aspect_align == SP_ASPECT_NONE) { - nr_arena_image_set_pixels(NR_ARENA_IMAGE(ai), - gdk_pixbuf_get_pixels(image->pixbuf), - gdk_pixbuf_get_width(image->pixbuf), - gdk_pixbuf_get_height(image->pixbuf), - rs); - } else { // preserveAspectRatio - nr_arena_image_set_pixels(NR_ARENA_IMAGE(ai), - gdk_pixbuf_get_pixels(image->pixbuf) + image->trimx*pixskip + image->trimy*rs, - image->trimwidth, - image->trimheight, - rs); - } - } else { - nr_arena_image_set_pixels(NR_ARENA_IMAGE(ai), NULL, 0, 0, 0); - } - if (image->aspect_align == SP_ASPECT_NONE) { - nr_arena_image_set_geometry(NR_ARENA_IMAGE(ai), image->x.computed, image->y.computed, image->width.computed, image->height.computed); - } else { // preserveAspectRatio - nr_arena_image_set_geometry(NR_ARENA_IMAGE(ai), image->viewx, image->viewy, image->viewwidth, image->viewheight); - } + sp_image_update_arenaitem(image, NR_ARENA_IMAGE(ai)); return ai; } @@ -1287,44 +1261,23 @@ static GdkPixbuf *sp_image_pixbuf_force_rgba( GdkPixbuf * pixbuf ) } /* We assert that realpixbuf is either NULL or identical size to pixbuf */ +static void +sp_image_update_arenaitem (SPImage *image, NRArenaImage *ai) +{ + nr_arena_image_set_style(ai, SP_OBJECT(image)->style); + nr_arena_image_set_argb32_pixbuf(ai, image->pixbuf); + nr_arena_image_set_origin(ai, Geom::Point(image->ox, image->oy)); + nr_arena_image_set_scale(ai, image->sx, image->sy); + nr_arena_image_set_clipbox(ai, image->clipbox); +} -static void sp_image_update_canvas_image( SPImage *image ) +static void +sp_image_update_canvas_image (SPImage *image) { SPItem *item = SP_ITEM(image); - if (image->pixbuf) { - /* fixme: We are slightly violating spec here (Lauris) */ - if (!image->width._set) { - image->width.computed = gdk_pixbuf_get_width(image->pixbuf); - } - if (!image->height._set) { - image->height.computed = gdk_pixbuf_get_height(image->pixbuf); - } - } - for (SPItemView *v = item->display; v != NULL; v = v->next) { - int pixskip = gdk_pixbuf_get_n_channels(image->pixbuf) * gdk_pixbuf_get_bits_per_sample(image->pixbuf) / 8; - int rs = gdk_pixbuf_get_rowstride(image->pixbuf); - nr_arena_image_set_style(NR_ARENA_IMAGE(v->arenaitem), image->style); - if (image->aspect_align == SP_ASPECT_NONE) { - nr_arena_image_set_pixels(NR_ARENA_IMAGE(v->arenaitem), - gdk_pixbuf_get_pixels(image->pixbuf), - gdk_pixbuf_get_width(image->pixbuf), - gdk_pixbuf_get_height(image->pixbuf), - rs); - nr_arena_image_set_geometry(NR_ARENA_IMAGE(v->arenaitem), - image->x.computed, image->y.computed, - image->width.computed, image->height.computed); - } else { // preserveAspectRatio - nr_arena_image_set_pixels(NR_ARENA_IMAGE(v->arenaitem), - gdk_pixbuf_get_pixels(image->pixbuf) + image->trimx*pixskip + image->trimy*rs, - image->trimwidth, - image->trimheight, - rs); - nr_arena_image_set_geometry(NR_ARENA_IMAGE(v->arenaitem), - image->viewx, image->viewy, - image->viewwidth, image->viewheight); - } + sp_image_update_arenaitem(image, NR_ARENA_IMAGE(v->arenaitem)); } } diff --git a/src/sp-image.h b/src/sp-image.h index 9618c9873..2b3940412 100644 --- a/src/sp-image.h +++ b/src/sp-image.h @@ -38,12 +38,16 @@ struct SPImage : public SPItem { SVGLength width; SVGLength height; + Geom::Rect clipbox; + double sx, sy; + double ox, oy; + // Added by EAF /* preserveAspectRatio */ unsigned int aspect_align : 4; unsigned int aspect_clip : 1; - int trimx, trimy, trimwidth, trimheight; - double viewx, viewy, viewwidth, viewheight; + //int trimx, trimy, trimwidth, trimheight; + //double viewx, viewy, viewwidth, viewheight; SPCurve *curve; // This curve is at the image's boundary for snapping diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index 91342688a..8d38fee07 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -24,8 +24,6 @@ #include "display/nr-arena-group.h" #include "display/curve.h" -#include "libnr/nr-matrix-ops.h" -#include "libnr/nr-matrix-fns.h" #include "xml/repr.h" #include "svg/svg.h" #include "document.h" @@ -707,7 +705,7 @@ void CGroup::calculateBBox(NRRect *bbox, Geom::Affine const &transform, unsigned SPObject *o = SP_OBJECT (l->data); if (SP_IS_ITEM(o) && !SP_ITEM(o)->isHidden()) { SPItem *child = SP_ITEM(o); - Geom::Affine const ct(to_2geom(child->transform) * transform); + Geom::Affine const ct(child->transform * transform); child->invoke_bbox_full( dummy_bbox, ct, flags, FALSE); } l = g_slist_remove (l, o); diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index e91c80b5f..ae55a5c50 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -122,7 +122,7 @@ get_scale_transform_with_stroke (Geom::Rect const &bbox_param, gdouble strokewid Geom::Affine direct_constant_r = Geom::Scale(flip_x * ratio_x, flip_y * ratio_y); - if (transform_stroke && r0 != 0 && r0 != NR_HUGE) { // there's stroke, and we need to scale it + if (transform_stroke && r0 != 0 && r0 != Geom::infinity()) { // there's stroke, and we need to scale it // These coefficients are obtained from the assumption that scaling applies to the // non-stroked "shape proper" and that stroke scale is scaled by the expansion of that // matrix. We're trying to solve this equation: @@ -147,7 +147,7 @@ get_scale_transform_with_stroke (Geom::Rect const &bbox_param, gdouble strokewid scale *= direct; } } else { - if (r0 == 0 || r0 == NR_HUGE) { // no stroke to scale + if (r0 == 0 || r0 == Geom::infinity()) { // no stroke to scale scale *= direct; } else {// nonscaling strokewidth scale *= direct_constant_r; @@ -174,7 +174,7 @@ get_visual_bbox (Geom::OptRect const &initial_geom_bbox, Geom::Affine const &abs } Geom::Rect new_visual_bbox = new_geom_bbox; - if (initial_strokewidth > 0 && initial_strokewidth < NR_HUGE) { + if (initial_strokewidth > 0 && initial_strokewidth < Geom::infinity()) { if (transform_stroke) { // scale stroke by: sqrt (((w1-r0)/(w0-r0))*((h1-r0)/(h0-r0))) (for visual bboxes, see get_scale_transform_with_stroke) // equals scaling by: sqrt ((w1/w0)*(h1/h0)) for geometrical bboxes diff --git a/src/sp-item.cpp b/src/sp-item.cpp index 40c9b0233..7e5f5f96a 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -61,11 +61,6 @@ #include "sp-title.h" #include "sp-desc.h" -#include "libnr/nr-matrix-fns.h" -#include "libnr/nr-matrix-scale-ops.h" -#include "libnr/nr-matrix-translate-ops.h" -#include "libnr/nr-scale-translate-ops.h" -#include "libnr/nr-translate-scale-ops.h" #include "libnr/nr-convert2geom.h" #include "util/find-last-if.h" #include "util/reverse-list.h" @@ -743,8 +738,8 @@ void SPItem::invoke_bbox_full( Geom::OptRect &bbox, Geom::Affine const &transfor // TODO: replace NRRect by Geom::Rect, for all SPItemClasses, and for SP_CLIPPATH NRRect temp_bbox; - temp_bbox.x0 = temp_bbox.y0 = NR_HUGE; - temp_bbox.x1 = temp_bbox.y1 = -NR_HUGE; + temp_bbox.x0 = temp_bbox.y0 = Geom::infinity(); + temp_bbox.x1 = temp_bbox.y1 = -Geom::infinity(); // call the subclass method if (((SPItemClass *) G_OBJECT_GET_CLASS(this))->bbox) { @@ -816,7 +811,7 @@ void SPItem::invoke_bbox_full( Geom::OptRect &bbox, Geom::Affine const &transfor if (temp_bbox.x0 > temp_bbox.x1 || temp_bbox.y0 > temp_bbox.y1) { // Either the bbox hasn't been touched by the SPItemClass' bbox method - // (it still has its initial values, see above: x0 = y0 = NR_HUGE and x1 = y1 = -NR_HUGE) + // (it still has its initial values, see above: x0 = y0 = Geom::infinity() and x1 = y1 = -Geom::infinity()) // or it has explicitely been set to be like this (e.g. in sp_shape_bbox) // When x0 > x1 or y0 > y1, the bbox is considered to be "nothing", although it has not been @@ -1190,7 +1185,9 @@ void SPItem::adjust_gradient( Geom::Affine const &postmul, bool set ) void SPItem::adjust_stroke( gdouble ex ) { - if ( style && !style->stroke.isNone() && !NR_DF_TEST_CLOSE(ex, 1.0, NR_EPSILON) ) { + SPStyle *style = this->style; + + if (style && !style->stroke.isNone() && !Geom::are_near(ex, 1.0, Geom::EPSILON)) { style->stroke_width.computed *= ex; style->stroke_width.set = TRUE; diff --git a/src/sp-line.cpp b/src/sp-line.cpp index 72fe2cfa2..b21122566 100644 --- a/src/sp-line.cpp +++ b/src/sp-line.cpp @@ -12,7 +12,7 @@ */ #ifdef HAVE_CONFIG_H -# include <config.h> +# include "config.h" #endif #include "attributes.h" #include "style.h" @@ -20,8 +20,7 @@ #include "sp-guide.h" #include "display/curve.h" #include <glibmm/i18n.h> -#include <libnr/nr-matrix-fns.h> -#include <xml/repr.h> +#include "xml/repr.h" #include "document.h" #include "inkscape.h" diff --git a/src/sp-mask.cpp b/src/sp-mask.cpp index 513e52911..76efb6b4b 100644 --- a/src/sp-mask.cpp +++ b/src/sp-mask.cpp @@ -16,7 +16,6 @@ #include "display/nr-arena.h" #include "display/nr-arena-group.h" -#include "libnr/nr-matrix-ops.h" #include <xml/repr.h> #include "enums.h" @@ -353,10 +352,10 @@ sp_mask_set_bbox (SPMask *mask, unsigned int key, NRRect *bbox) { for (SPMaskView *v = mask->display; v != NULL; v = v->next) { if (v->key == key) { - if (!NR_DF_TEST_CLOSE (v->bbox.x0, bbox->x0, NR_EPSILON) || - !NR_DF_TEST_CLOSE (v->bbox.y0, bbox->y0, NR_EPSILON) || - !NR_DF_TEST_CLOSE (v->bbox.x1, bbox->x1, NR_EPSILON) || - !NR_DF_TEST_CLOSE (v->bbox.y1, bbox->y1, NR_EPSILON)) { + if (!Geom::are_near(v->bbox.x0, bbox->x0) || + !Geom::are_near(v->bbox.y0, bbox->y0) || + !Geom::are_near(v->bbox.x1, bbox->x1) || + !Geom::are_near(v->bbox.y1, bbox->y1)) { v->bbox = *bbox; } break; diff --git a/src/sp-object-repr.cpp b/src/sp-object-repr.cpp index a995739b1..c6d6729cc 100644 --- a/src/sp-object-repr.cpp +++ b/src/sp-object-repr.cpp @@ -58,7 +58,6 @@ #include "color-profile-fns.h" #include "xml/repr.h" #include "sp-filter.h" -#include "sp-gaussian-blur.h" #include "filters/blend.h" #include "filters/colormatrix.h" #include "filters/componenttransfer.h" @@ -69,6 +68,7 @@ #include "filters/distantlight.h" #include "filters/displacementmap.h" #include "filters/flood.h" +#include "filters/gaussian-blur.h" #include "filters/image.h" #include "filters/merge.h" #include "filters/morphology.h" diff --git a/src/sp-offset.cpp b/src/sp-offset.cpp index 3fb9441a3..460421492 100644 --- a/src/sp-offset.cpp +++ b/src/sp-offset.cpp @@ -36,7 +36,7 @@ #include "sp-use-reference.h" #include "uri.h" -#include <libnr/nr-matrix-fns.h> +#include <2geom/affine.h> #include <2geom/pathvector.h> #include "xml/repr.h" diff --git a/src/sp-paint-server.cpp b/src/sp-paint-server.cpp index 18b1eea7d..dc99639c8 100644 --- a/src/sp-paint-server.cpp +++ b/src/sp-paint-server.cpp @@ -14,7 +14,6 @@ */ #include <string.h> -#include "libnr/nr-pixblock-pattern.h" #include "sp-paint-server-reference.h" #include "sp-paint-server.h" @@ -23,13 +22,9 @@ static void sp_paint_server_class_init(SPPaintServerClass *psc); -static void sp_paint_server_release(SPObject *object); - -static void sp_painter_stale_fill(SPPainter *painter, NRPixBlock *pb); +static cairo_pattern_t *sp_paint_server_create_dummy_pattern(SPPaintServer *ps, cairo_t *ct, NRRect const *bbox, double opacity); static SPObjectClass *parent_class; -static GSList *stale_painters = NULL; - SPPaintServer *SPPaintServerReference::getObject() const { @@ -41,7 +36,7 @@ bool SPPaintServerReference::_acceptObject(SPObject *obj) const return SP_IS_PAINT_SERVER(obj); } -GType SPPaintServer::getType(void) +GType SPPaintServer::get_type(void) { static GType type = 0; if (!type) { @@ -64,108 +59,43 @@ GType SPPaintServer::getType(void) static void sp_paint_server_class_init(SPPaintServerClass *psc) { - SPObjectClass *sp_object_class = (SPObjectClass *) psc; - sp_object_class->release = sp_paint_server_release; + psc->pattern_new = sp_paint_server_create_dummy_pattern; + parent_class = (SPObjectClass *) g_type_class_ref(SP_TYPE_OBJECT); } void SPPaintServer::init(SPPaintServer *ps) { - ps->painters = NULL; - ps->swatch = false; } -static void sp_paint_server_release(SPObject *object) -{ - SPPaintServer *ps = SP_PAINT_SERVER(object); - - while (ps->painters) { - SPPainter *painter = ps->painters; - ps->painters = painter->next; - stale_painters = g_slist_prepend(stale_painters, painter); - painter->next = NULL; - painter->server = NULL; - painter->fill = sp_painter_stale_fill; - } - - if (((SPObjectClass *) parent_class)->release) { - ((SPObjectClass *) parent_class)->release(object); - } -} - -SPPainter *sp_paint_server_painter_new(SPPaintServer *ps, - Geom::Affine const &full_transform, - Geom::Affine const &parent_transform, - const NRRect *bbox) +cairo_pattern_t *sp_paint_server_create_pattern(SPPaintServer *ps, + cairo_t *ct, + NRRect const *bbox, + double opacity) { + // NOTE: the ct argument is used for when rendering patterns + // to create a group, instead of explicitly creating a temporary surface g_return_val_if_fail(ps != NULL, NULL); g_return_val_if_fail(SP_IS_PAINT_SERVER(ps), NULL); g_return_val_if_fail(bbox != NULL, NULL); - SPPainter *painter = NULL; - SPPaintServerClass *psc = SP_PAINT_SERVER_CLASS( G_OBJECT_GET_CLASS(ps) ); - if ( psc->painter_new ) { - painter = (*psc->painter_new)(ps, full_transform, parent_transform, bbox); - } - - if (painter) { - painter->next = ps->painters; - painter->server = ps; - painter->server_type = G_OBJECT_TYPE(ps); - ps->painters = painter; - } - - return painter; -} - -static void sp_paint_server_painter_free(SPPaintServer *ps, SPPainter *painter) -{ - g_return_if_fail(ps != NULL); - g_return_if_fail(SP_IS_PAINT_SERVER(ps)); - g_return_if_fail(painter != NULL); - - SPPaintServerClass *psc = SP_PAINT_SERVER_CLASS( G_OBJECT_GET_CLASS(ps) ); - - SPPainter *r = NULL; - for (SPPainter *p = ps->painters; p != NULL; p = p->next) { - if (p == painter) { - if (r) { - r->next = p->next; - } else { - ps->painters = p->next; - } - p->next = NULL; - if (psc->painter_free) { - (*psc->painter_free) (ps, painter); - } - return; - } - r = p; + cairo_pattern_t *cp = NULL; + SPPaintServerClass *psc = (SPPaintServerClass *) G_OBJECT_GET_CLASS(ps); + if ( psc->pattern_new ) { + cp = (*psc->pattern_new)(ps, ct, bbox, opacity); } - g_assert_not_reached(); + return cp; } -SPPainter *sp_painter_free(SPPainter *painter) +static cairo_pattern_t * +sp_paint_server_create_dummy_pattern(SPPaintServer */*ps*/, + cairo_t */* ct */, + NRRect const */*bbox*/, + double /* opacity */) { - g_return_val_if_fail(painter != NULL, NULL); - - if (painter->server) { - sp_paint_server_painter_free(painter->server, painter); - } else { - SPPaintServerClass *psc = SP_PAINT_SERVER_CLASS( g_type_class_ref(painter->server_type) ); - if (psc->painter_free) { - (*psc->painter_free)(NULL, painter); - } - stale_painters = g_slist_remove(stale_painters, painter); - } - - return NULL; -} - -static void sp_painter_stale_fill(SPPainter */*painter*/, NRPixBlock *pb) -{ - nr_pixblock_render_gray_noise(pb, NULL); + cairo_pattern_t *cp = cairo_pattern_create_rgb(1.0, 0.0, 1.0); + return cp; } bool SPPaintServer::isSwatch() const @@ -185,9 +115,6 @@ bool SPPaintServer::isSolid() const return solid; } - - - /* Local Variables: mode:c++ diff --git a/src/sp-paint-server.h b/src/sp-paint-server.h index c77aad694..283a97210 100644 --- a/src/sp-paint-server.h +++ b/src/sp-paint-server.h @@ -15,40 +15,24 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <libnr/nr-pixblock.h> +#include <cairo.h> #include "sp-object.h" #include "uri-references.h" -struct SPPainter; -struct SPPaintServer; +struct NRRect; -#define SP_TYPE_PAINT_SERVER (SPPaintServer::getType()) +#define SP_TYPE_PAINT_SERVER (SPPaintServer::get_type()) #define SP_PAINT_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_PAINT_SERVER, SPPaintServer)) #define SP_PAINT_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_PAINT_SERVER, SPPaintServerClass)) #define SP_IS_PAINT_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_PAINT_SERVER)) #define SP_IS_PAINT_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_PAINT_SERVER)) -typedef void (* SPPainterFillFunc) (SPPainter *painter, NRPixBlock *pb); - - -/* fixme: I do not like that class thingie (Lauris) */ -struct SPPainter { - SPPainter *next; - SPPaintServer *server; - GType server_type; -// SPPainterType type; - SPPainterFillFunc fill; -}; - struct SPPaintServer : public SPObject { - /** List of paints */ - SPPainter *painters; - protected: bool swatch; public: - static GType getType(void); + static GType get_type(void); bool isSwatch() const; bool isSolid() const; @@ -60,14 +44,10 @@ private: struct SPPaintServerClass { SPObjectClass sp_object_class; /** Get SPPaint instance. */ - SPPainter * (* painter_new) (SPPaintServer *ps, Geom::Affine const &full_transform, Geom::Affine const &parent_transform, const NRRect *bbox); - /** Free SPPaint instance. */ - void (* painter_free) (SPPaintServer *ps, SPPainter *painter); + cairo_pattern_t *(*pattern_new)(SPPaintServer *ps, cairo_t *ct, const NRRect *bbox, double opacity); }; -SPPainter *sp_paint_server_painter_new (SPPaintServer *ps, Geom::Affine const &full_transform, Geom::Affine const &parent_transform, const NRRect *bbox); - -SPPainter *sp_painter_free (SPPainter *painter); +cairo_pattern_t *sp_paint_server_create_pattern(SPPaintServer *ps, cairo_t *ct, NRRect const *bbox, double opacity); #endif // SEEN_SP_PAINT_SERVER_H diff --git a/src/sp-path.cpp b/src/sp-path.cpp index 9a27af2f0..c8022d351 100644 --- a/src/sp-path.cpp +++ b/src/sp-path.cpp @@ -24,8 +24,7 @@ #include "live_effects/lpeobject-reference.h" #include "sp-lpe-item.h" -#include <display/curve.h> -#include <libnr/nr-matrix-fns.h> +#include "display/curve.h" #include <2geom/pathvector.h> #include <2geom/bezier-curve.h> #include <2geom/hvlinesegment.h> diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index d7522fce8..d1e7671ed 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -18,11 +18,10 @@ #include <cstring> #include <string> -#include <libnr/nr-matrix-ops.h> -#include "libnr/nr-matrix-fns.h" #include <2geom/transforms.h> #include "macros.h" #include "svg/svg.h" +#include "display/cairo-utils.h" #include "display/nr-arena.h" #include "display/nr-arena-group.h" #include "attributes.h" @@ -39,46 +38,21 @@ * Pattern */ -class SPPatPainter; - -struct SPPatPainter { - SPPainter painter; - SPPattern *pat; - - Geom::Affine ps2px; - Geom::Affine px2ps; - Geom::Affine pcs2px; - - NRArena *arena; - unsigned int dkey; - NRArenaItem *root; - - bool use_cached_tile; - Geom::Affine ca2pa; - Geom::Affine pa2ca; - NRRectL cached_bbox; - NRPixBlock cached_tile; - - std::map<SPObject *, sigc::connection> *_release_connections; -}; - static void sp_pattern_class_init (SPPatternClass *klass); static void sp_pattern_init (SPPattern *gr); static void sp_pattern_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); static void sp_pattern_release (SPObject *object); static void sp_pattern_set (SPObject *object, unsigned int key, const gchar *value); -static void sp_pattern_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref); static void sp_pattern_update (SPObject *object, SPCtx *ctx, unsigned int flags); static void sp_pattern_modified (SPObject *object, unsigned int flags); static void pattern_ref_changed(SPObject *old_ref, SPObject *ref, SPPattern *pat); static void pattern_ref_modified (SPObject *ref, guint flags, SPPattern *pattern); -static SPPainter *sp_pattern_painter_new (SPPaintServer *ps, Geom::Affine const &full_transform, Geom::Affine const &parent_transform, const NRRect *bbox); -static void sp_pattern_painter_free (SPPaintServer *ps, SPPainter *painter); +static cairo_pattern_t *sp_pattern_create_pattern(SPPaintServer *ps, cairo_t *ct, NRRect const *bbox, double opacity); -static SPPaintServerClass * pattern_parent_class = 0; +static SPPaintServerClass * pattern_parent_class; GType sp_pattern_get_type (void) @@ -105,22 +79,23 @@ sp_pattern_get_type (void) static void sp_pattern_class_init (SPPatternClass *klass) { - SPObjectClass *sp_object_class = SP_OBJECT_CLASS( klass ); - SPPaintServerClass *ps_class = SP_PAINT_SERVER_CLASS( klass ); + SPObjectClass *sp_object_class; + SPPaintServerClass *ps_class; - pattern_parent_class = SP_PAINT_SERVER_CLASS( g_type_class_ref(SP_TYPE_PAINT_SERVER) ); + sp_object_class = (SPObjectClass *) klass; + ps_class = (SPPaintServerClass *) klass; + + pattern_parent_class = (SPPaintServerClass*)g_type_class_ref (SP_TYPE_PAINT_SERVER); sp_object_class->build = sp_pattern_build; sp_object_class->release = sp_pattern_release; sp_object_class->set = sp_pattern_set; - sp_object_class->child_added = sp_pattern_child_added; sp_object_class->update = sp_pattern_update; sp_object_class->modified = sp_pattern_modified; // do we need _write? seems to work without it - ps_class->painter_new = sp_pattern_painter_new; - ps_class->painter_free = sp_pattern_painter_free; + ps_class->pattern_new = sp_pattern_create_pattern; } static void @@ -135,7 +110,7 @@ sp_pattern_init (SPPattern *pat) pat->patternContentUnits = SP_PATTERN_UNITS_USERSPACEONUSE; pat->patternContentUnits_set = FALSE; - pat->patternTransform = NR::identity(); + pat->patternTransform = Geom::identity(); pat->patternTransform_set = FALSE; pat->x.unset(); @@ -229,7 +204,7 @@ sp_pattern_set (SPObject *object, unsigned int key, const gchar *value) pat->patternTransform = t; pat->patternTransform_set = TRUE; } else { - pat->patternTransform = NR::identity(); + pat->patternTransform = Geom::identity(); pat->patternTransform_set = FALSE; } object->requestModified(SP_OBJECT_MODIFIED_FLAG); @@ -311,34 +286,6 @@ sp_pattern_set (SPObject *object, unsigned int key, const gchar *value) } } -static void -sp_pattern_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) -{ - SPPattern *pat = SP_PATTERN (object); - - if (((SPObjectClass *) (pattern_parent_class))->child_added) - (* ((SPObjectClass *) (pattern_parent_class))->child_added) (object, child, ref); - - SPObject *ochild = object->get_child_by_repr(child); - if (SP_IS_ITEM (ochild)) { - - SPPaintServer *ps = SP_PAINT_SERVER (pat); - unsigned position = SP_ITEM(ochild)->pos_in_parent(); - - for (SPPainter *p = ps->painters; p != NULL; p = p->next) { - - SPPatPainter *pp = (SPPatPainter *) p; - NRArenaItem *ai = SP_ITEM (ochild)->invoke_show (pp->arena, pp->dkey, SP_ITEM_REFERENCE_FLAGS); - - if (ai) { - nr_arena_item_add_child (pp->root, ai, NULL); - nr_arena_item_set_order (ai, position); - nr_arena_item_unref (ai); - } - } - } -} - /* TODO: do we need a ::remove_child handler? */ /* fixme: We need ::order_changed handler too (Lauris) */ @@ -651,401 +598,134 @@ bool pattern_hasItemChildren (SPPattern *pat) return hasChildren; } - - -/* Painter */ - -static void sp_pat_fill (SPPainter *painter, NRPixBlock *pb); - -// item in this pattern is about to be deleted, hide it on our arena and disconnect -void -sp_pattern_painter_release (SPObject *obj, SPPatPainter *painter) -{ - std::map<SPObject *, sigc::connection>::iterator iter = painter->_release_connections->find(obj); - if (iter != painter->_release_connections->end()) { - iter->second.disconnect(); - painter->_release_connections->erase(obj); - } - - SP_ITEM(obj)->invoke_hide(painter->dkey); -} - -/** -Creates a painter (i.e. the thing that does actual filling at the given zoom). -See (*) below for why the parent_transform may be necessary. -*/ -static SPPainter * -sp_pattern_painter_new (SPPaintServer *ps, Geom::Affine const &full_transform, Geom::Affine const &/*parent_transform*/, const NRRect *bbox) +static cairo_pattern_t * +sp_pattern_create_pattern(SPPaintServer *ps, + cairo_t *base_ct, + NRRect const *bbox, + double opacity) { - SPPattern *pat = SP_PATTERN (ps); - SPPatPainter *pp = g_new (SPPatPainter, 1); - - pp->painter.server_type = G_OBJECT_TYPE(ps); - pp->painter.fill = sp_pat_fill; - - pp->pat = pat; - - if (pattern_patternUnits (pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { - /* BBox to user coordinate system */ - Geom::Affine bbox2user (bbox->x1 - bbox->x0, 0.0, 0.0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0); + SPPattern *pat = SP_PATTERN (ps); + Geom::Affine ps2user; + Geom::Affine vb2ps = Geom::identity(); + bool needs_opacity = (1.0 - opacity) >= 1e-3; + bool visible = opacity >= 1e-3; - // the final patternTransform, taking into account bbox - Geom::Affine const ps2user(pattern_patternTransform(pat) * bbox2user); + if (!visible) + return NULL; - // see (*) comment below - pp->ps2px = ps2user * full_transform; - } else { - /* Problem: What to do, if we have mixed lengths and percentages? */ - /* Currently we do ignore percentages at all, but that is not good (lauris) */ - - /* fixme: We may try to normalize here too, look at linearGradient (Lauris) */ - - // (*) The spec says, "This additional transformation matrix [patternTransform] is - // post-multiplied to (i.e., inserted to the right of) any previously defined - // transformations, including the implicit transformation necessary to convert from - // object bounding box units to user space." To me, this means that the order should be: - // item_transform * patternTransform * parent_transform - // However both Batik and Adobe plugin use: - // patternTransform * item_transform * parent_transform - // So here I comply with the majority opinion, but leave my interpretation commented out below. - // (To get item_transform, I subtract parent from full.) - - //pp->ps2px = (full_transform / parent_transform) * pattern_patternTransform(pat) * parent_transform; - pp->ps2px = pattern_patternTransform(pat) * full_transform; - } + /* Show items */ + SPPattern *shown = NULL; + for (SPPattern *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { + // find the first one with item children + if (pat_i && SP_IS_OBJECT (pat_i) && pattern_hasItemChildren(pat_i)) { + shown = pat_i; + break; // do not go further up the chain if children are found + } + } - pp->px2ps = pp->ps2px.inverse(); + if (!shown) { + return cairo_pattern_create_rgba(0,0,0,0); + } - if (pat->viewBox_set) { - gdouble tmp_x = pattern_width (pat) / (pattern_viewBox(pat)->x1 - pattern_viewBox(pat)->x0); - gdouble tmp_y = pattern_height (pat) / (pattern_viewBox(pat)->y1 - pattern_viewBox(pat)->y0); + /* Create arena */ + NRArena *arena = NRArena::create(); + unsigned int dkey = SPItem::display_key_new (1); + NRArenaGroup *root = NRArenaGroup::create(arena); + + for (SPObject *child = shown->firstChild(); child != NULL; child = child->getNext() ) { + if (SP_IS_ITEM (child)) { + // for each item in pattern, show it on our arena, add to the group, + // and connect to the release signal in case the item gets deleted + NRArenaItem *cai; + cai = SP_ITEM(child)->invoke_show (arena, dkey, SP_ITEM_SHOW_DISPLAY); + nr_arena_item_append_child (root, cai); + } + } - // FIXME: preserveAspectRatio must be taken into account here too! - Geom::Affine vb2ps (tmp_x, 0.0, 0.0, tmp_y, pattern_x(pat) - pattern_viewBox(pat)->x0 * tmp_x, pattern_y(pat) - pattern_viewBox(pat)->y0 * tmp_y); + if (pat->viewBox_set) { + gdouble tmp_x = pattern_width (pat) / (pattern_viewBox(pat)->x1 - pattern_viewBox(pat)->x0); + gdouble tmp_y = pattern_height (pat) / (pattern_viewBox(pat)->y1 - pattern_viewBox(pat)->y0); - Geom::Affine vb2us = vb2ps * pattern_patternTransform(pat); + // FIXME: preserveAspectRatio must be taken into account here too! + vb2ps = Geom::Affine(tmp_x, 0.0, 0.0, tmp_y, pattern_x(pat) - pattern_viewBox(pat)->x0 * tmp_x, pattern_y(pat) - pattern_viewBox(pat)->y0 * tmp_y); + } - // see (*) - pp->pcs2px = vb2us * full_transform; - } else { - /* No viewbox, have to parse units */ - if (pattern_patternContentUnits (pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { - /* BBox to user coordinate system */ - Geom::Affine bbox2user (bbox->x1 - bbox->x0, 0.0, 0.0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0); + ps2user = pattern_patternTransform(pat); + if (!pat->viewBox_set && pattern_patternContentUnits (pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { + /* BBox to user coordinate system */ + Geom::Affine bbox2user (bbox->x1 - bbox->x0, 0.0, 0.0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0); + ps2user *= bbox2user; + } + ps2user = Geom::Translate (pattern_x (pat), pattern_y (pat)) * ps2user; - Geom::Affine pcs2user = pattern_patternTransform(pat) * bbox2user; + Geom::Point p(pattern_x(pat), pattern_y(pat)); + Geom::Point pd(pattern_width(pat), pattern_height(pat)); + Geom::Rect pattern_tile(p, p + pd); - // see (*) - pp->pcs2px = pcs2user * full_transform; - } else { - // see (*) - //pcs2px = (full_transform / parent_transform) * pattern_patternTransform(pat) * parent_transform; - pp->pcs2px = pattern_patternTransform(pat) * full_transform; - } + if (pattern_patternUnits(pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { + // interpret x, y, width, height in relation to bbox + Geom::Affine bbox2user(bbox->x1 - bbox->x0, 0,0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0); + pattern_tile = pattern_tile * bbox2user; + } - pp->pcs2px = Geom::Translate (pattern_x (pat), pattern_y (pat)) * pp->pcs2px; - } + cairo_matrix_t cm; + cairo_get_matrix(base_ct, &cm); + Geom::Affine full(cm.xx, cm.yx, cm.xy, cm.yy, 0, 0); + + // oversample the pattern slightly + // TODO: find optimum value + Geom::Point c(pattern_tile.dimensions()*ps2user.descrim()*full.descrim()*1.2); + c[Geom::X] = ceil(c[Geom::X]); + c[Geom::Y] = ceil(c[Geom::Y]); + Geom::Affine t = Geom::Scale(c) * Geom::Scale(pattern_tile.dimensions()).inverse(); + + NRRectL one_tile; + one_tile.x0 = (int) floor(pattern_tile[Geom::X].min()); + one_tile.y0 = (int) floor(pattern_tile[Geom::Y].min()); + one_tile.x1 = (int) ceil(pattern_tile[Geom::X].max()); + one_tile.y1 = (int) ceil(pattern_tile[Geom::Y].max()); + + cairo_surface_t *target = cairo_get_target(base_ct); + cairo_surface_t *temp = cairo_surface_create_similar(target, CAIRO_CONTENT_COLOR_ALPHA, + c[Geom::X], c[Geom::Y]); + cairo_t *ct = cairo_create(temp); + // scale into a coord system where the surface w,h are equal to tile w,h + ink_cairo_transform(ct, t); + + // render pattern. + if (needs_opacity) { + cairo_push_group(ct); // this group is for pattern + opacity + } - /* Create arena */ - pp->arena = NRArena::create(); - - pp->dkey = SPItem::display_key_new (1); - - /* Create group */ - pp->root = NRArenaGroup::create(pp->arena); - - /* Show items */ - pp->_release_connections = new std::map<SPObject *, sigc::connection>; - for (SPPattern *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { - if (pat_i && SP_IS_OBJECT (pat_i) && pattern_hasItemChildren(pat_i)) { // find the first one with item children - for (SPObject *child = pat_i->firstChild() ; child; child = child->getNext() ) { - if (SP_IS_ITEM (child)) { - // for each item in pattern, - // show it on our arena, - NRArenaItem *cai = SP_ITEM(child)->invoke_show(pp->arena, pp->dkey, SP_ITEM_REFERENCE_FLAGS); - // add to the group, - nr_arena_item_append_child (pp->root, cai); - // and connect to the release signal in case the item gets deleted - pp->_release_connections->insert(std::make_pair(child, child->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_pattern_painter_release), pp)))); - } - } - break; // do not go further up the chain if children are found - } + // TODO: make sure there are no leaks. + NRGC gc(NULL); + gc.transform = vb2ps; + nr_arena_item_invoke_update (root, NULL, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_ALL); + nr_arena_item_invoke_render (ct, root, &one_tile, NULL, 0); + for (SPObject *child = shown->firstChild() ; child != NULL; child = child->getNext() ) { + if (SP_IS_ITEM (child)) { + SP_ITEM(child)->invoke_hide(dkey); } + } + nr_object_unref(root); + nr_object_unref(arena); - { - NRRect one_tile,tr_tile; - one_tile.x0=pattern_x(pp->pat); - one_tile.y0=pattern_y(pp->pat); - one_tile.x1=one_tile.x0+pattern_width (pp->pat); - one_tile.y1=one_tile.y0+pattern_height (pp->pat); - // TODO: remove ps2px_nr after converting to 2geom - NR::Matrix ps2px_nr = from_2geom(pp->ps2px); - nr_rect_d_matrix_transform (&tr_tile, &one_tile, &ps2px_nr); - int tr_width=(int)ceil(1.3*(tr_tile.x1-tr_tile.x0)); - int tr_height=(int)ceil(1.3*(tr_tile.y1-tr_tile.y0)); -// if ( tr_width < 10000 && tr_height < 10000 && tr_width*tr_height < 1000000 ) { - pp->use_cached_tile=false;//true; - if ( tr_width > 1000 ) tr_width=1000; - if ( tr_height > 1000 ) tr_height=1000; - pp->cached_bbox.x0=0; - pp->cached_bbox.y0=0; - pp->cached_bbox.x1=tr_width; - pp->cached_bbox.y1=tr_height; - - if (pp->use_cached_tile) { - nr_pixblock_setup (&pp->cached_tile,NR_PIXBLOCK_MODE_R8G8B8A8N, pp->cached_bbox.x0, pp->cached_bbox.y0, pp->cached_bbox.x1, pp->cached_bbox.y1,TRUE); - } - - pp->pa2ca[0]=((double)tr_width)/(one_tile.x1-one_tile.x0); - pp->pa2ca[1]=0; - pp->pa2ca[2]=0; - pp->pa2ca[3]=((double)tr_height)/(one_tile.y1-one_tile.y0); - pp->pa2ca[4]=-one_tile.x0*pp->pa2ca[0]; - pp->pa2ca[5]=-one_tile.y0*pp->pa2ca[1]; - pp->ca2pa[0]=(one_tile.x1-one_tile.x0)/((double)tr_width); - pp->ca2pa[1]=0; - pp->ca2pa[2]=0; - pp->ca2pa[3]=(one_tile.y1-one_tile.y0)/((double)tr_height); - pp->ca2pa[4]=one_tile.x0; - pp->ca2pa[5]=one_tile.y0; -// } else { -// pp->use_cached_tile=false; -// } - } - - NRGC gc(NULL); - if ( pp->use_cached_tile ) { - gc.transform=pp->pa2ca; - } else { - gc.transform = pp->pcs2px; - } - nr_arena_item_invoke_update (pp->root, NULL, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_ALL); - if ( pp->use_cached_tile ) { - nr_arena_item_invoke_render (NULL, pp->root, &pp->cached_bbox, &pp->cached_tile, 0); - } else { - // nothing to do now - } - - return (SPPainter *) pp; -} - - -static void -sp_pattern_painter_free (SPPaintServer */*ps*/, SPPainter *painter) -{ - SPPatPainter *pp = (SPPatPainter *) painter; - // free our arena - if (pp->arena) { - ((NRObject *) pp->arena)->unreference(); - pp->arena = NULL; - } - - // disconnect all connections - std::map<SPObject *, sigc::connection>::iterator iter; - for (iter = pp->_release_connections->begin() ; iter!=pp->_release_connections->end() ; iter++) { - iter->second.disconnect(); - } - pp->_release_connections->clear(); - delete pp->_release_connections; + if (needs_opacity) { + cairo_pop_group_to_source(ct); // pop raw pattern + cairo_paint_with_alpha(ct, opacity); // apply opacity + } - if ( pp->use_cached_tile ) nr_pixblock_release(&pp->cached_tile); - g_free (pp); -} + cairo_pattern_t *cp = cairo_pattern_create_for_surface(temp); + cairo_destroy(ct); + cairo_surface_destroy(temp); -void -get_cached_tile_pixel(SPPatPainter* pp,double x,double y,unsigned char &r,unsigned char &g,unsigned char &b,unsigned char &a) -{ - int ca_h=(int)floor(x); - int ca_v=(int)floor(y); - int r_x=(int)floor(16*(x-floor(x))); - int r_y=(int)floor(16*(y-floor(y))); - unsigned int tl_m=(16-r_x)*(16-r_y); - unsigned int bl_m=(16-r_x)*r_y; - unsigned int tr_m=r_x*(16-r_y); - unsigned int br_m=r_x*r_y; - int cb_h=ca_h+1; - int cb_v=ca_v+1; - if ( cb_h >= pp->cached_bbox.x1 ) cb_h=0; - if ( cb_v >= pp->cached_bbox.y1 ) cb_v=0; - - unsigned char* tlx=NR_PIXBLOCK_PX(&pp->cached_tile)+(ca_v*pp->cached_tile.rs)+4*ca_h; - unsigned char* trx=NR_PIXBLOCK_PX(&pp->cached_tile)+(ca_v*pp->cached_tile.rs)+4*cb_h; - unsigned char* blx=NR_PIXBLOCK_PX(&pp->cached_tile)+(cb_v*pp->cached_tile.rs)+4*ca_h; - unsigned char* brx=NR_PIXBLOCK_PX(&pp->cached_tile)+(cb_v*pp->cached_tile.rs)+4*cb_h; - - unsigned int tl_c=tlx[0]; - unsigned int tr_c=trx[0]; - unsigned int bl_c=blx[0]; - unsigned int br_c=brx[0]; - unsigned int f_c=(tl_m*tl_c+tr_m*tr_c+bl_m*bl_c+br_m*br_c)>>8; - r=f_c; - tl_c=tlx[1]; - tr_c=trx[1]; - bl_c=blx[1]; - br_c=brx[1]; - f_c=(tl_m*tl_c+tr_m*tr_c+bl_m*bl_c+br_m*br_c)>>8; - g=f_c; - tl_c=tlx[2]; - tr_c=trx[2]; - bl_c=blx[2]; - br_c=brx[2]; - f_c=(tl_m*tl_c+tr_m*tr_c+bl_m*bl_c+br_m*br_c)>>8; - b=f_c; - tl_c=tlx[3]; - tr_c=trx[3]; - bl_c=blx[3]; - br_c=brx[3]; - f_c=(tl_m*tl_c+tr_m*tr_c+bl_m*bl_c+br_m*br_c)>>8; - a=f_c; -} + // Apply transformation to user space. Also compensate for oversampling. + ink_cairo_pattern_set_matrix(cp, ps2user.inverse() * t); + cairo_pattern_set_extend(cp, CAIRO_EXTEND_REPEAT); -static void -sp_pat_fill (SPPainter *painter, NRPixBlock *pb) -{ - SPPatPainter *pp; - NRRect ba, psa; - NRRectL area; - double x, y; - - pp = (SPPatPainter *) painter; - - if (pattern_width (pp->pat) < NR_EPSILON) return; - if (pattern_height (pp->pat) < NR_EPSILON) return; - - bool grayscale = Grayscale::activeDesktopIsGrayscale(); // TODO: find good way to access the current rendermode - - /* Find buffer area in gradient space */ - /* fixme: This is suboptimal (Lauris) */ - - if ( !grayscale && pp->use_cached_tile ) { - double pat_w=pattern_width (pp->pat); - double pat_h=pattern_height (pp->pat); - if ( pb->mode == NR_PIXBLOCK_MODE_R8G8B8A8N || pb->mode == NR_PIXBLOCK_MODE_R8G8B8A8P ) { // same thing because it's filling an empty pixblock - unsigned char* lpx=NR_PIXBLOCK_PX(pb); - double px_y=pb->area.y0; - for (int j=pb->area.y0;j<pb->area.y1;j++) { - unsigned char* cpx=lpx; - double px_x = pb->area.x0; - - double ps_x=pp->px2ps[0]*px_x+pp->px2ps[2]*px_y+pp->px2ps[4]; - double ps_y=pp->px2ps[1]*px_x+pp->px2ps[3]*px_y+pp->px2ps[5]; - for (int i=pb->area.x0;i<pb->area.x1;i++) { - while ( ps_x > pat_w ) ps_x-=pat_w; - while ( ps_x < 0 ) ps_x+=pat_w; - while ( ps_y > pat_h ) ps_y-=pat_h; - while ( ps_y < 0 ) ps_y+=pat_h; - double ca_x=pp->pa2ca[0]*ps_x+pp->pa2ca[2]*ps_y+pp->pa2ca[4]; - double ca_y=pp->pa2ca[1]*ps_x+pp->pa2ca[3]*ps_y+pp->pa2ca[5]; - unsigned char n_a,n_r,n_g,n_b; - get_cached_tile_pixel(pp,ca_x,ca_y,n_r,n_g,n_b,n_a); - cpx[0]=n_r; - cpx[1]=n_g; - cpx[2]=n_b; - cpx[3]=n_a; - - px_x+=1.0; - ps_x+=pp->px2ps[0]; - ps_y+=pp->px2ps[1]; - cpx+=4; - } - px_y+=1.0; - lpx+=pb->rs; - } - } else if ( pb->mode == NR_PIXBLOCK_MODE_R8G8B8 ) { - unsigned char* lpx=NR_PIXBLOCK_PX(pb); - double px_y=pb->area.y0; - for (int j=pb->area.y0;j<pb->area.y1;j++) { - unsigned char* cpx=lpx; - double px_x = pb->area.x0; - - double ps_x=pp->px2ps[0]*px_x+pp->px2ps[2]*px_y+pp->px2ps[4]; - double ps_y=pp->px2ps[1]*px_x+pp->px2ps[3]*px_y+pp->px2ps[5]; - for (int i=pb->area.x0;i<pb->area.x1;i++) { - while ( ps_x > pat_w ) ps_x-=pat_w; - while ( ps_x < 0 ) ps_x+=pat_w; - while ( ps_y > pat_h ) ps_y-=pat_h; - while ( ps_y < 0 ) ps_y+=pat_h; - double ca_x=pp->pa2ca[0]*ps_x+pp->pa2ca[2]*ps_y+pp->pa2ca[4]; - double ca_y=pp->pa2ca[1]*ps_x+pp->pa2ca[3]*ps_y+pp->pa2ca[5]; - unsigned char n_a,n_r,n_g,n_b; - get_cached_tile_pixel(pp,ca_x,ca_y,n_r,n_g,n_b,n_a); - cpx[0]=n_r; - cpx[1]=n_g; - cpx[2]=n_b; - - px_x+=1.0; - ps_x+=pp->px2ps[0]; - ps_y+=pp->px2ps[1]; - cpx+=4; - } - px_y+=1.0; - lpx+=pb->rs; - } - } - } else { - ba.x0 = pb->area.x0; - ba.y0 = pb->area.y0; - ba.x1 = pb->area.x1; - ba.y1 = pb->area.y1; - - // Trying to solve this bug: https://bugs.launchpad.net/inkscape/+bug/167416 - // Bail out if the transformation matrix has extreme values. If we bail out - // however, then something (which was meaningless anyway) won't be rendered, - // which is better than getting stuck in a virtually infinite loop - if (fabs(pp->px2ps[0]) < 1e6 && - fabs(pp->px2ps[3]) < 1e6 && - fabs(pp->px2ps[4]) < 1e6 && - fabs(pp->px2ps[5]) < 1e6) - { - // TODO: remove px2ps_nr after converting to 2geom - NR::Matrix px2ps_nr = from_2geom(pp->px2ps); - nr_rect_d_matrix_transform (&psa, &ba, &px2ps_nr); - - psa.x0 = floor ((psa.x0 - pattern_x (pp->pat)) / pattern_width (pp->pat)) -1; - psa.y0 = floor ((psa.y0 - pattern_y (pp->pat)) / pattern_height (pp->pat)) -1; - psa.x1 = ceil ((psa.x1 - pattern_x (pp->pat)) / pattern_width (pp->pat)) +1; - psa.y1 = ceil ((psa.y1 - pattern_y (pp->pat)) / pattern_height (pp->pat)) +1; - - // If psa is too wide or tall, then something must be wrong! This is due to - // nr_rect_d_matrix_transform (&psa, &ba, &pp->px2ps) using a weird transformation matrix pp->px2ps. - g_assert(std::abs(psa.x1 - psa.x0) < 1e6); - g_assert(std::abs(psa.y1 - psa.y0) < 1e6); - - for (y = psa.y0; y < psa.y1; y++) { - for (x = psa.x0; x < psa.x1; x++) { - NRPixBlock ppb; - double psx, psy; - - psx = x * pattern_width (pp->pat); - psy = y * pattern_height (pp->pat); - - area.x0 = (gint32)(pb->area.x0 - (pp->ps2px[0] * psx + pp->ps2px[2] * psy)); - area.y0 = (gint32)(pb->area.y0 - (pp->ps2px[1] * psx + pp->ps2px[3] * psy)); - area.x1 = area.x0 + pb->area.x1 - pb->area.x0; - area.y1 = area.y0 + pb->area.y1 - pb->area.y0; - - // We do not update here anymore - - // Set up buffer - // fixme: (Lauris) - nr_pixblock_setup_extern (&ppb, pb->mode, area.x0, area.y0, area.x1, area.y1, NR_PIXBLOCK_PX (pb), pb->rs, FALSE, FALSE); - - Inkscape::ColorRenderMode saved_colormode = pp->root->arena->colorrendermode; - if (grayscale) { - pp->root->arena->colorrendermode = Inkscape::COLORRENDERMODE_GRAYSCALE; - } - nr_arena_item_invoke_render (NULL, pp->root, &area, &ppb, 0); - pp->root->arena->colorrendermode = saved_colormode; - - nr_pixblock_release (&ppb); - } - } - } - } + return cp; } - /* Local Variables: mode:c++ @@ -1055,4 +735,4 @@ sp_pat_fill (SPPainter *painter, NRPixBlock *pb) fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/sp-pattern.h b/src/sp-pattern.h index 64544b3dc..1f545bfc4 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -28,7 +28,6 @@ GType sp_pattern_get_type (void); class SPPatternClass; #include <libnr/nr-rect.h> -#include <libnr/nr-matrix.h> #include "svg/svg-length.h" #include "sp-paint-server.h" #include "uri-references.h" diff --git a/src/sp-rect.cpp b/src/sp-rect.cpp index e8f79e6ed..94a453ae6 100644 --- a/src/sp-rect.cpp +++ b/src/sp-rect.cpp @@ -16,9 +16,7 @@ #endif -#include <display/curve.h> -#include <libnr/nr-matrix-ops.h> -#include <libnr/nr-matrix-fns.h> +#include "display/curve.h" #include <2geom/rect.h> #include "inkscape.h" diff --git a/src/sp-root.cpp b/src/sp-root.cpp index 8286bfc4f..b1eef65d2 100644 --- a/src/sp-root.cpp +++ b/src/sp-root.cpp @@ -27,11 +27,6 @@ #include "document.h" #include "sp-defs.h" #include "sp-root.h" -#include <libnr/nr-matrix-fns.h> -#include <libnr/nr-matrix-ops.h> -#include <libnr/nr-matrix-translate-ops.h> -#include <libnr/nr-scale-ops.h> -#include <libnr/nr-translate-scale-ops.h> #include <xml/repr.h> #include "svg/stringstream.h" #include "inkscape-version.h" diff --git a/src/sp-shape.cpp b/src/sp-shape.cpp index 358e2a595..ea79b6cee 100644 --- a/src/sp-shape.cpp +++ b/src/sp-shape.cpp @@ -18,10 +18,6 @@ # include "config.h" #endif -#include <libnr/nr-matrix-fns.h> -#include <libnr/nr-matrix-ops.h> -#include <libnr/nr-matrix-translate-ops.h> -#include <libnr/nr-scale-matrix-ops.h> #include <2geom/rect.h> #include <2geom/transforms.h> #include <2geom/pathvector.h> @@ -249,7 +245,7 @@ void SPShape::sp_shape_update(SPObject *object, SPCtx *ctx, unsigned int flags) SPStyle *style = object->style; if (style->stroke_width.unit == SP_CSS_UNIT_PERCENT) { SPItemCtx *ictx = (SPItemCtx *) ctx; - double const aw = 1.0 / NR::expansion(ictx->i2vp); + double const aw = 1.0 / ictx->i2vp.descrim(); style->stroke_width.computed = style->stroke_width.value * aw; for (SPItemView *v = ((SPItem *) (shape))->display; v != NULL; v = v->next) { nr_arena_shape_set_style ((NRArenaShape *) v->arenaitem, style); @@ -589,7 +585,7 @@ void SPShape::sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const // get bbox of the marker with that transform NRRect marker_bbox; - marker_item->invoke_bbox ( &marker_bbox, from_2geom(tr), true); + marker_item->invoke_bbox ( &marker_bbox, tr, true); // union it with the shape bbox nr_rect_d_union (&cbbox, &cbbox, &marker_bbox); } @@ -617,7 +613,7 @@ void SPShape::sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const } tr = marker_item->transform * marker->c2p * tr * transform; NRRect marker_bbox; - marker_item->invoke_bbox ( &marker_bbox, from_2geom(tr), true); + marker_item->invoke_bbox ( &marker_bbox, tr, true); nr_rect_d_union (&cbbox, &cbbox, &marker_bbox); } // MID position @@ -644,7 +640,7 @@ void SPShape::sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const } tr = marker_item->transform * marker->c2p * tr * transform; NRRect marker_bbox; - marker_item->invoke_bbox ( &marker_bbox, from_2geom(tr), true); + marker_item->invoke_bbox ( &marker_bbox, tr, true); nr_rect_d_union (&cbbox, &cbbox, &marker_bbox); } diff --git a/src/sp-star.cpp b/src/sp-star.cpp index 92d8cd7a5..39efe2537 100644 --- a/src/sp-star.cpp +++ b/src/sp-star.cpp @@ -19,6 +19,7 @@ #include <cstring> #include <string> +#include <glib.h> #include <glibmm/i18n.h> #include "svg/svg.h" @@ -175,7 +176,7 @@ sp_star_set (SPObject *object, unsigned int key, const gchar *value) case SP_ATTR_SODIPODI_SIDES: if (value) { star->sides = atoi (value); - star->sides = NR_CLAMP(star->sides, 3, 1024); + star->sides = CLAMP(star->sides, 3, 1024); } else { star->sides = 5; } @@ -528,13 +529,13 @@ sp_star_position_set (SPStar *star, gint sides, Geom::Point center, gdouble r1, g_return_if_fail (star != NULL); g_return_if_fail (SP_IS_STAR (star)); - star->sides = NR_CLAMP(sides, 3, 1024); + star->sides = CLAMP(sides, 3, 1024); star->center = center; star->r[0] = MAX (r1, 0.001); if (isflat == false) { - star->r[1] = NR_CLAMP(r2, 0.0, star->r[0]); + star->r[1] = CLAMP(r2, 0.0, star->r[0]); } else { - star->r[1] = NR_CLAMP( r1*cos(M_PI/sides) ,0.0, star->r[0] ); + star->r[1] = CLAMP( r1*cos(M_PI/sides) ,0.0, star->r[0] ); } star->arg[0] = arg1; star->arg[1] = arg2; diff --git a/src/sp-symbol.cpp b/src/sp-symbol.cpp index 70ab4d173..1d4bdec0f 100644 --- a/src/sp-symbol.cpp +++ b/src/sp-symbol.cpp @@ -17,8 +17,6 @@ #include <cstring> #include <string> -#include "libnr/nr-matrix-fns.h" -#include "libnr/nr-matrix-ops.h" #include <2geom/transforms.h> #include "display/nr-arena-group.h" #include "xml/repr.h" diff --git a/src/sp-symbol.h b/src/sp-symbol.h index 6c0a36d73..120591459 100644 --- a/src/sp-symbol.h +++ b/src/sp-symbol.h @@ -24,7 +24,6 @@ class SPSymbol; class SPSymbolClass; -#include <libnr/nr-matrix.h> #include <2geom/affine.h> #include <libnr/nr-rect.h> #include "svg/svg-length.h" diff --git a/src/sp-text.cpp b/src/sp-text.cpp index 57f9dd14e..3f30c2422 100644 --- a/src/sp-text.cpp +++ b/src/sp-text.cpp @@ -28,7 +28,6 @@ #endif #include <2geom/affine.h> -#include <libnr/nr-matrix-fns.h> #include <libnrtype/FontFactory.h> #include <libnrtype/font-instance.h> #include <libnrtype/font-style-to-pos.h> @@ -624,7 +623,7 @@ void SPText::_adjustFontsizeRecursive(SPItem *item, double ex, bool is_root) { SPStyle *style = item->style; - if (style && !NR_DF_TEST_CLOSE (ex, 1.0, NR_EPSILON)) { + if (style && !Geom::are_near(ex, 1.0)) { if (!style->font_size.set && is_root) { style->font_size.set = 1; } diff --git a/src/sp-tref.cpp b/src/sp-tref.cpp index 7c4976a11..b301add7f 100644 --- a/src/sp-tref.cpp +++ b/src/sp-tref.cpp @@ -33,7 +33,6 @@ #include "uri.h" #include "display/nr-arena-group.h" -#include "libnr/nr-matrix-fns.h" #include "xml/node.h" #include "xml/repr.h" diff --git a/src/sp-tspan.cpp b/src/sp-tspan.cpp index 14e7452fe..199d82e1b 100644 --- a/src/sp-tspan.cpp +++ b/src/sp-tspan.cpp @@ -40,7 +40,6 @@ #include "sp-textpath.h" #include "text-editing.h" #include "style.h" -#include "libnr/nr-matrix-fns.h" #include "xml/repr.h" #include "document.h" @@ -593,9 +592,10 @@ sp_textpath_to_text(SPObject *tp) { SPObject *text = tp->parent; - NRRect bbox; - SP_ITEM(text)->invoke_bbox( &bbox, SP_ITEM(text)->i2doc_affine(), TRUE); - Geom::Point xy(bbox.x0, bbox.y0); + Geom::OptRect bbox; + SP_ITEM(text)->invoke_bbox(bbox, SP_ITEM(text)->i2doc_affine(), TRUE); + if (!bbox) return; + Geom::Point xy = bbox->min(); // make a list of textpath children GSList *tp_reprs = NULL; diff --git a/src/sp-use.cpp b/src/sp-use.cpp index a92dbcaa9..a05b28a5f 100644 --- a/src/sp-use.cpp +++ b/src/sp-use.cpp @@ -20,8 +20,6 @@ #include <cstring> #include <string> -#include <libnr/nr-matrix-ops.h> -#include <libnr/nr-matrix-fns.h> #include <2geom/transforms.h> #include <glibmm/i18n.h> #include "display/nr-arena-group.h" diff --git a/src/splivarot.cpp b/src/splivarot.cpp index 5ff394782..3d3027639 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -45,7 +45,6 @@ #include "xml/repr.h" #include "xml/repr-sorting.h" #include <2geom/pathvector.h> -#include <libnr/nr-scale-matrix-ops.h> #include "helper/geom.h" #include "livarot/Path.h" diff --git a/src/spray-context.cpp b/src/spray-context.cpp index 553edf69b..36c135924 100644 --- a/src/spray-context.cpp +++ b/src/spray-context.cpp @@ -35,13 +35,9 @@ #include "desktop.h" #include "desktop-events.h" #include "desktop-handles.h" -#include "unistd.h" -//#include "desktop-style.h" #include "message-context.h" #include "pixmaps/cursor-spray.xpm" #include <boost/optional.hpp> -#include "libnr/nr-matrix-ops.h" -#include "libnr/nr-scale-translate-ops.h" #include "xml/repr.h" #include "context-fns.h" #include "sp-item.h" diff --git a/src/star-context.cpp b/src/star-context.cpp index 0fb20a2ab..9f4afb94c 100644 --- a/src/star-context.cpp +++ b/src/star-context.cpp @@ -457,14 +457,14 @@ static void sp_star_drag(SPStarContext *sc, Geom::Point p, guint state) double const sides = (gdouble) sc->magnitude; Geom::Point const d = p1 - p0; Geom::Coord const r1 = Geom::L2(d); - double arg1 = atan2(from_2geom(d)); + double arg1 = atan2(d); if (state & GDK_CONTROL_MASK) { /* Snap angle */ arg1 = sp_round(arg1, M_PI / snaps); } - sp_star_position_set(star, sc->magnitude, from_2geom(p0), r1, r1 * sc->proportion, + sp_star_position_set(star, sc->magnitude, p0, r1, r1 * sc->proportion, arg1, arg1 + M_PI / sides, sc->isflatsided, sc->rounded, sc->randomized); /* status text */ diff --git a/src/svg/svg-affine.cpp b/src/svg/svg-affine.cpp index 69685e04c..a986e5986 100644 --- a/src/svg/svg-affine.cpp +++ b/src/svg/svg-affine.cpp @@ -20,11 +20,8 @@ #include <cstdlib> #include <cstdio> #include <glib/gstrfuncs.h> -#include <libnr/nr-matrix-fns.h> -#include <libnr/nr-matrix-ops.h> #include <2geom/transforms.h> #include <2geom/angle.h> -#include <libnr/nr-convert2geom.h> #include "svg.h" #include "preferences.h" diff --git a/src/text-chemistry.cpp b/src/text-chemistry.cpp index b1b31b6f6..873c214a7 100644 --- a/src/text-chemistry.cpp +++ b/src/text-chemistry.cpp @@ -19,7 +19,6 @@ #include <string> #include <glibmm/i18n.h> -#include "libnr/nr-matrix-fns.h" #include "xml/repr.h" #include "sp-rect.h" #include "sp-textpath.h" @@ -151,7 +150,7 @@ text_put_on_path() Inkscape::Text::Layout::Alignment text_alignment = layout->paragraphAlignment(layout->begin()); // remove transform from text, but recursively scale text's fontsize by the expansion - SP_TEXT(text)->_adjustFontsizeRecursive (text, NR::expansion(SP_ITEM(text)->transform)); + SP_TEXT(text)->_adjustFontsizeRecursive (text, SP_ITEM(text)->transform.descrim()); text->getRepr()->setAttribute("transform", NULL); // make a list of text children @@ -317,7 +316,7 @@ text_flow_into_shape() if (SP_IS_TEXT(text)) { // remove transform from text, but recursively scale text's fontsize by the expansion - SP_TEXT(text)->_adjustFontsizeRecursive(text, NR::expansion(SP_ITEM(text)->transform)); + SP_TEXT(text)->_adjustFontsizeRecursive(text, SP_ITEM(text)->transform.descrim()); text->getRepr()->setAttribute("transform", NULL); } @@ -433,10 +432,10 @@ text_unflow () /* Set style */ rtext->setAttribute("style", flowtext->getRepr()->attribute("style")); // fixme: transfer style attrs too; and from descendants - NRRect bbox; - SP_ITEM(flowtext)->invoke_bbox( &bbox, SP_ITEM(flowtext)->i2doc_affine(), TRUE); - Geom::Point xy(bbox.x0, bbox.y0); - if (xy[Geom::X] != 1e18 && xy[Geom::Y] != 1e18) { + Geom::OptRect bbox; + SP_ITEM(flowtext)->invoke_bbox(bbox, SP_ITEM(flowtext)->i2doc_affine(), TRUE); + if (bbox) { + Geom::Point xy = bbox->min(); sp_repr_set_svg_double(rtext, "x", xy[Geom::X]); sp_repr_set_svg_double(rtext, "y", xy[Geom::Y]); } diff --git a/src/text-editing.cpp b/src/text-editing.cpp index 003af245d..18264fa56 100644 --- a/src/text-editing.cpp +++ b/src/text-editing.cpp @@ -1160,7 +1160,7 @@ sp_te_adjust_tspan_letterspacing_screen(SPItem *text, Inkscape::Text::Layout::it gdouble const zoom = desktop->current_zoom(); gdouble const zby = (by / (zoom * (nb_let > 1 ? nb_let - 1 : 1)) - / to_2geom(SP_ITEM(source_obj)->i2doc_affine()).descrim()); + / SP_ITEM(source_obj)->i2doc_affine().descrim()); val += zby; if (start == end) { diff --git a/src/trace/trace.cpp b/src/trace/trace.cpp index 1ee32e6bf..813f532a4 100644 --- a/src/trace/trace.cpp +++ b/src/trace/trace.cpp @@ -16,24 +16,23 @@ #include "trace/potrace/inkscape-potrace.h" -#include <inkscape.h> -#include <desktop.h> -#include <desktop-handles.h> -#include <document.h> -#include <message-stack.h> +#include "inkscape.h" +#include "desktop.h" +#include "desktop-handles.h" +#include "document.h" +#include "message-stack.h" #include <gtkmm.h> #include <glibmm/i18n.h> -#include <selection.h> -#include <xml/repr.h> -#include <xml/attribute-record.h> -#include <sp-item.h> -#include <sp-shape.h> -#include <sp-image.h> -#include <libnr/nr-matrix-ops.h> +#include "selection.h" +#include "xml/repr.h" +#include "xml/attribute-record.h" +#include "sp-item.h" +#include "sp-shape.h" +#include "sp-image.h" #include <2geom/transforms.h> -#include <display/nr-arena.h> -#include <display/nr-arena-shape.h> +#include "display/nr-arena.h" +#include "display/nr-arena-shape.h" #include "siox.h" #include "imagemap-gdk.h" diff --git a/src/transf_mat_3x4.h b/src/transf_mat_3x4.h index 69174d9df..8542e5e00 100644 --- a/src/transf_mat_3x4.h +++ b/src/transf_mat_3x4.h @@ -29,7 +29,7 @@ public: void toggle_finite (Proj::Axis axis); double get_infinite_angle (Proj::Axis axis) { if (has_finite_image(axis)) { - return 1e18; //this used to be NR_HUGE before 2geom conversion + return Geom::infinity(); } Pt2 vp(column(axis)); return Geom::atan2(Geom::Point(vp[0], vp[1])) * 180.0/M_PI; diff --git a/src/tweak-context.cpp b/src/tweak-context.cpp index aef7dfba9..faa08ee91 100644 --- a/src/tweak-context.cpp +++ b/src/tweak-context.cpp @@ -39,8 +39,6 @@ #include "pixmaps/cursor-roughen.xpm" #include "pixmaps/cursor-color.xpm" #include <boost/optional.hpp> -#include "libnr/nr-matrix-ops.h" -#include "libnr/nr-scale-translate-ops.h" #include "xml/repr.h" #include "context-fns.h" #include "sp-item.h" @@ -72,8 +70,7 @@ #include "box3d.h" #include "sp-item-transform.h" #include "filter-chemistry.h" -#include "sp-gaussian-blur-fns.h" -#include "sp-gaussian-blur.h" +#include "filters/gaussian-blur.h" #include "tweak-context.h" diff --git a/src/ui/cache/svg_preview_cache.cpp b/src/ui/cache/svg_preview_cache.cpp index a7ad1701d..fd7070bab 100644 --- a/src/ui/cache/svg_preview_cache.cpp +++ b/src/ui/cache/svg_preview_cache.cpp @@ -28,6 +28,7 @@ #include "document-private.h" #include "display/nr-arena.h" #include "display/nr-arena-item.h" +#include "display/cairo-utils.h" #include "ui/cache/svg_preview_cache.h" @@ -44,10 +45,10 @@ GdkPixbuf* render_pixbuf(NRArenaItem* root, double scale_factor, const Geom::Rec /* Item integer bbox in points */ NRRectL ibox; - ibox.x0 = (int) floor(scale_factor * dbox.min()[Geom::X] + 0.5); - ibox.y0 = (int) floor(scale_factor * dbox.min()[Geom::Y] + 0.5); - ibox.x1 = (int) floor(scale_factor * dbox.max()[Geom::X] + 0.5); - ibox.y1 = (int) floor(scale_factor * dbox.max()[Geom::Y] + 0.5); + ibox.x0 = floor(scale_factor * dbox.min()[Geom::X]); + ibox.y0 = floor(scale_factor * dbox.min()[Geom::Y]); + ibox.x1 = ceil(scale_factor * dbox.max()[Geom::X]); + ibox.y1 = ceil(scale_factor * dbox.max()[Geom::Y]); /* Find visible area */ int width = ibox.x1 - ibox.x0; @@ -63,34 +64,24 @@ GdkPixbuf* render_pixbuf(NRArenaItem* root, double scale_factor, const Geom::Rec area.x1 = area.x0 + psize; area.y1 = area.y0 + psize; - /* Actual renderable area */ - NRRectL ua; - ua.x0 = std::max(ibox.x0, area.x0); - ua.y0 = std::max(ibox.y0, area.y0); - ua.x1 = std::min(ibox.x1, area.x1); - ua.y1 = std::min(ibox.y1, area.y1); - - /* Set up pixblock */ - guchar *px = g_new(guchar, 4 * psize * psize); - memset(px, 0x00, 4 * psize * psize); - /* Render */ - NRPixBlock B; - nr_pixblock_setup_extern( &B, NR_PIXBLOCK_MODE_R8G8B8A8N, - ua.x0, ua.y0, ua.x1, ua.y1, - px + 4 * psize * (ua.y0 - area.y0) + - 4 * (ua.x0 - area.x0), - 4 * psize, FALSE, FALSE ); - nr_arena_item_invoke_render(NULL, root, &ua, &B, + cairo_surface_t *s = cairo_image_surface_create( + CAIRO_FORMAT_ARGB32, psize, psize); + cairo_t *ct = cairo_create(s); + cairo_translate(ct, -area.x0, -area.y0); + + nr_arena_item_invoke_render(ct, root, &area, NULL, NR_ARENA_ITEM_RENDER_NO_CACHE ); - nr_pixblock_release(&B); + cairo_surface_flush(s); + cairo_destroy(ct); - GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(px, + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(cairo_image_surface_get_data(s), GDK_COLORSPACE_RGB, TRUE, - 8, psize, psize, psize * 4, - (GdkPixbufDestroyNotify)g_free, + 8, psize, psize, cairo_image_surface_get_stride(s), + (GdkPixbufDestroyNotify)cairo_surface_destroy, NULL); + convert_pixbuf_argb32_to_normal(pixbuf); return pixbuf; } diff --git a/src/ui/dialog/color-item.cpp b/src/ui/dialog/color-item.cpp index da8393fc5..89245575c 100644 --- a/src/ui/dialog/color-item.cpp +++ b/src/ui/dialog/color-item.cpp @@ -13,6 +13,7 @@ #include <errno.h> #include <glibmm/i18n.h> #include <gtkmm/label.h> +#include <cairo.h> #include <gtk/gtk.h> #include "color-item.h" @@ -20,7 +21,7 @@ #include "desktop.h" #include "desktop-handles.h" #include "desktop-style.h" -#include "display/nr-plain-stuff.h" +#include "display/cairo-utils.h" #include "document.h" #include "inkscape.h" // for SP_ACTIVE_DESKTOP #include "io/resource.h" @@ -212,17 +213,20 @@ static void colorItemDragBegin( GtkWidget */*widget*/, GdkDragContext* dc, gpoin } else { GdkPixbuf* pixbuf = 0; if ( item->getGradient() ){ - guchar* px = g_new( guchar, 3 * height * width ); - nr_render_checkerboard_rgb( px, width, height, 3 * width, 0, 0 ); - - sp_gradient_render_vector_block_rgb( item->getGradient(), - px, width, height, 3 * width, - 0, width, TRUE ); - - pixbuf = gdk_pixbuf_new_from_data( px, GDK_COLORSPACE_RGB, FALSE, 8, - width, height, width * 3, - 0, // add delete function - 0 ); + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + cairo_pattern_t *gradient = sp_gradient_create_preview_pattern(item->getGradient(), width); + cairo_t *ct = cairo_create(s); + cairo_set_source(ct, gradient); + cairo_paint(ct); + cairo_destroy(ct); + cairo_pattern_destroy(gradient); + cairo_surface_flush(s); + + pixbuf = gdk_pixbuf_new_from_data(cairo_image_surface_get_data(s), + GDK_COLORSPACE_RGB, TRUE, 8, + width, height, cairo_image_surface_get_stride(s), + (GdkPixbufDestroyNotify) cairo_surface_destroy, NULL); + convert_pixbuf_argb32_to_normal(pixbuf); } else { Glib::RefPtr<Gdk::Pixbuf> thumb = Gdk::Pixbuf::create( Gdk::COLORSPACE_RGB, false, 8, width, height ); guint32 fillWith = (0xff000000 & (item->def.getR() << 24)) @@ -252,10 +256,8 @@ static void colorItemDragBegin( GtkWidget */*widget*/, GdkDragContext* dc, gpoin // } -SwatchPage::SwatchPage() : - _name(), - _prefWidth(0), - _colors() +SwatchPage::SwatchPage() + : _prefWidth(0) { } @@ -265,10 +267,7 @@ SwatchPage::~SwatchPage() ColorItem::ColorItem(ege::PaintDef::ColorType type) : - Previewable(), def(type), - tips(), - _previews(), _isFill(false), _isStroke(false), _isLive(false), @@ -277,18 +276,12 @@ ColorItem::ColorItem(ege::PaintDef::ColorType type) : _linkGray(0), _linkSrc(0), _grad(0), - _pixData(0), - _pixWidth(0), - _pixHeight(0), - _listeners() + _pattern(0) { } ColorItem::ColorItem( unsigned int r, unsigned int g, unsigned int b, Glib::ustring& name ) : - Previewable(), def( r, g, b, name ), - tips(), - _previews(), _isFill(false), _isStroke(false), _isLive(false), @@ -297,15 +290,15 @@ ColorItem::ColorItem( unsigned int r, unsigned int g, unsigned int b, Glib::ustr _linkGray(0), _linkSrc(0), _grad(0), - _pixData(0), - _pixWidth(0), - _pixHeight(0), - _listeners() + _pattern(0) { } ColorItem::~ColorItem() { + if (_pattern != NULL) { + cairo_pattern_destroy(_pattern); + } } ColorItem::ColorItem(ColorItem const &other) : @@ -361,18 +354,16 @@ void ColorItem::setGradient(SPGradient *grad) } } -void ColorItem::setPixData(guchar* px, int width, int height) +void ColorItem::setPattern(cairo_pattern_t *pattern) { - if (px != _pixData) { - if (_pixData) { - g_free(_pixData); - } - _pixData = px; - _pixWidth = width; - _pixHeight = height; - - _updatePreviews(); + if (pattern) { + cairo_pattern_reference(pattern); + } + if (_pattern) { + cairo_pattern_destroy(_pattern); } + _pattern = pattern; + _updatePreviews(); } void ColorItem::_dragGetColorData( GtkWidget */*widget*/, @@ -520,16 +511,28 @@ void ColorItem::_regenPreview(EekPreview * preview) eek_preview_set_pixbuf( preview, pixbuf ); } - else if ( !_pixData ){ + else if ( !_pattern ){ eek_preview_set_color( preview, (def.getR() << 8) | def.getR(), (def.getG() << 8) | def.getG(), (def.getB() << 8) | def.getB() ); } else { - GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( _pixData, GDK_COLORSPACE_RGB, FALSE, 8, - _pixWidth, _pixHeight, _pixWidth * 3, - 0, // add delete function - 0 ); + double w; + cairo_pattern_get_linear_points(_pattern, NULL, NULL, &w, NULL); + int width = ceil(w); + + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, 1); + cairo_t *ct = cairo_create(s); + cairo_set_source(ct, _pattern); + cairo_paint(ct); + cairo_destroy(ct); + cairo_surface_flush(s); + + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( cairo_image_surface_get_data(s), + GDK_COLORSPACE_RGB, TRUE, 8, + width, 1, cairo_image_surface_get_stride(s), + (GdkPixbufDestroyNotify) cairo_surface_destroy, NULL); + convert_pixbuf_argb32_to_normal(pixbuf); eek_preview_set_pixbuf( preview, pixbuf ); } diff --git a/src/ui/dialog/color-item.h b/src/ui/dialog/color-item.h index a6e344ce3..9080498eb 100644 --- a/src/ui/dialog/color-item.h +++ b/src/ui/dialog/color-item.h @@ -58,8 +58,7 @@ public: void setGradient(SPGradient *grad); SPGradient * getGradient() const { return _grad; } - - void setPixData(guchar* px, int width, int height); + void setPattern(cairo_pattern_t *pattern); void setState( bool fill, bool stroke ); bool isFill() { return _isFill; } @@ -104,9 +103,7 @@ private: int _linkGray; ColorItem* _linkSrc; SPGradient* _grad; - guchar *_pixData; - int _pixWidth; - int _pixHeight; + cairo_pattern_t *_pattern; std::vector<ColorItem*> _listeners; }; diff --git a/src/ui/dialog/filedialogimpl-win32.cpp b/src/ui/dialog/filedialogimpl-win32.cpp index 09c3d0a52..e83aeccad 100644 --- a/src/ui/dialog/filedialogimpl-win32.cpp +++ b/src/ui/dialog/filedialogimpl-win32.cpp @@ -29,15 +29,13 @@ //Inkscape includes #include "inkscape.h" -#include <dialogs/dialog-events.h> -#include <extension/input.h> -#include <extension/output.h> -#include <extension/db.h> - -#include <libnr/nr-pixops.h> -#include <libnr/nr-translate-scale-ops.h> -#include <display/nr-arena-item.h> -#include <display/nr-arena.h> +#include "dialogs/dialog-events.h" +#include "extension/input.h" +#include "extension/output.h" +#include "extension/db.h" + +#include "display/nr-arena-item.h" +#include "display/nr-arena.h" #include "sp-item.h" #include "display/canvas-arena.h" @@ -955,6 +953,10 @@ void FileOpenDialogImplWin32::free_preview() bool FileOpenDialogImplWin32::set_svg_preview() { + return false; + // NOTE: it's not worth the effort to fix this to use Cairo. + // Native file dialogs are unmaintainable and should be removed anyway. + #if 0 const int PreviewSize = 512; gchar *utf8string = g_utf16_to_utf8((const gunichar2*)_path_string, @@ -1055,6 +1057,7 @@ bool FileOpenDialogImplWin32::set_svg_preview() _mutex->unlock(); return true; + #endif } void FileOpenDialogImplWin32::destroy_svg_rendering(const guint8 *buffer) diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index 2e17daa11..c6d81b070 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -48,13 +48,13 @@ #include "filters/convolvematrix.h" #include "filters/displacementmap.h" #include "filters/distantlight.h" +#include "filters/gaussian-blur.h" #include "filters/merge.h" #include "filters/mergenode.h" #include "filters/offset.h" #include "filters/pointlight.h" #include "filters/spotlight.h" #include "sp-filter-primitive.h" -#include "sp-gaussian-blur.h" #include "style.h" #include "svg/svg-color.h" diff --git a/src/ui/dialog/icon-preview.cpp b/src/ui/dialog/icon-preview.cpp index bb566fb7f..4d98793bb 100644 --- a/src/ui/dialog/icon-preview.cpp +++ b/src/ui/dialog/icon-preview.cpp @@ -39,7 +39,7 @@ extern "C" { // takes doc, root, icon, and icon name to produce pixels guchar * sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, - const gchar *name, unsigned int psize ); + const gchar *name, unsigned int psize, unsigned &stride); } #define noICON_VERBOSE 1 @@ -167,10 +167,11 @@ IconPreviewPanel::IconPreviewPanel() : int previous = 0; int avail = 0; for ( int i = numEntries - 1; i >= 0; --i ) { - pixMem[i] = new guchar[4 * sizes[i] * sizes[i]]; - memset( pixMem[i], 0x00, 4 * sizes[i] * sizes[i] ); + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, sizes[i]); + pixMem[i] = new guchar[sizes[i] * stride]; + memset( pixMem[i], 0x00, sizes[i] * stride ); - GdkPixbuf *pb = gdk_pixbuf_new_from_data( pixMem[i], GDK_COLORSPACE_RGB, TRUE, 8, sizes[i], sizes[i], sizes[i] * 4, /*(GdkPixbufDestroyNotify)g_free*/NULL, NULL ); + GdkPixbuf *pb = gdk_pixbuf_new_from_data( pixMem[i], GDK_COLORSPACE_RGB, TRUE, 8, sizes[i], sizes[i], stride, /*(GdkPixbufDestroyNotify)g_free*/NULL, NULL ); GtkImage* img = GTK_IMAGE( gtk_image_new_from_pixbuf( pb ) ); images[i] = Glib::wrap(img); Glib::ustring label(*labels[i]); @@ -449,14 +450,16 @@ void IconPreviewPanel::renderPreview( SPObject* obj ) root = SP_ITEM( doc->getRoot() )->invoke_show( arena, visionkey, SP_ITEM_SHOW_DISPLAY ); for ( int i = 0; i < numEntries; i++ ) { - guchar * px = sp_icon_doc_icon( doc, root, id, sizes[i] ); + unsigned unused; + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, sizes[i]); + guchar * px = sp_icon_doc_icon( doc, root, id, sizes[i], unused); // g_message( " size %d %s", sizes[i], (px ? "worked" : "failed") ); if ( px ) { - memcpy( pixMem[i], px, sizes[i] * sizes[i] * 4 ); + memcpy( pixMem[i], px, sizes[i] * stride ); g_free( px ); px = 0; } else { - memset( pixMem[i], 0, sizes[i] * sizes[i] * 4 ); + memset( pixMem[i], 0, sizes[i] * stride ); } images[i]->queue_draw(); } diff --git a/src/ui/dialog/swatches.cpp b/src/ui/dialog/swatches.cpp index cbae7c26f..ad3b79630 100644 --- a/src/ui/dialog/swatches.cpp +++ b/src/ui/dialog/swatches.cpp @@ -46,7 +46,7 @@ #include "widgets/desktop-widget.h" #include "widgets/gradient-vector.h" #include "widgets/eek-preview.h" -#include "display/nr-plain-stuff.h" +#include "display/cairo-utils.h" #include "sp-gradient-reference.h" #include "dialog-manager.h" @@ -886,7 +886,7 @@ void SwatchesPanel::_setDocument( SPDocument *document ) static void recalcSwatchContents(SPDocument* doc, std::vector<ColorItem*> &tmpColors, - std::map<ColorItem*, guchar*> &previewMappings, + std::map<ColorItem*, cairo_pattern_t*> &previewMappings, std::map<ColorItem*, SPGradient*> &gradMappings) { std::vector<SPGradient*> newList; @@ -904,30 +904,29 @@ static void recalcSwatchContents(SPDocument* doc, for ( std::vector<SPGradient*>::iterator it = newList.begin(); it != newList.end(); ++it ) { SPGradient* grad = *it; - grad->ensureVector(); - SPGradientStop first = grad->vector.stops[0]; - SPColor color = first.color; - guint32 together = color.toRGBA32(first.opacity); - SPGradientStop second = (*it)->vector.stops[1]; - SPColor color2 = second.color; + cairo_surface_t *preview = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + PREVIEW_PIXBUF_WIDTH, VBLOCK); + cairo_t *ct = cairo_create(preview); Glib::ustring name( grad->getId() ); - unsigned int r = SP_RGBA32_R_U(together); - unsigned int g = SP_RGBA32_G_U(together); - unsigned int b = SP_RGBA32_B_U(together); - ColorItem* item = new ColorItem( r, g, b, name ); + ColorItem* item = new ColorItem( 0, 0, 0, name ); - gint width = PREVIEW_PIXBUF_WIDTH; - gint height = VBLOCK; - guchar* px = g_new( guchar, 3 * height * width ); - nr_render_checkerboard_rgb( px, width, height, 3 * width, 0, 0 ); + cairo_pattern_t *check = ink_cairo_pattern_create_checkerboard(); + cairo_pattern_t *gradient = sp_gradient_create_preview_pattern(grad, PREVIEW_PIXBUF_WIDTH); + cairo_set_source(ct, check); + cairo_paint(ct); + cairo_set_source(ct, gradient); + cairo_paint(ct); - sp_gradient_render_vector_block_rgb( grad, - px, width, height, 3 * width, - 0, width, TRUE ); + cairo_destroy(ct); + cairo_pattern_destroy(gradient); + cairo_pattern_destroy(check); - previewMappings[item] = px; + cairo_pattern_t *prevpat = cairo_pattern_create_for_surface(preview); + cairo_surface_destroy(preview); + + previewMappings[item] = prevpat; tmpColors.push_back(item); gradMappings[item] = grad; @@ -940,12 +939,13 @@ void SwatchesPanel::handleGradientsChange(SPDocument *document) SwatchPage *docPalette = (docPalettes.find(document) != docPalettes.end()) ? docPalettes[document] : 0; if (docPalette) { std::vector<ColorItem*> tmpColors; - std::map<ColorItem*, guchar*> tmpPrevs; + std::map<ColorItem*, cairo_pattern_t*> tmpPrevs; std::map<ColorItem*, SPGradient*> tmpGrads; recalcSwatchContents(document, tmpColors, tmpPrevs, tmpGrads); - for (std::map<ColorItem*, guchar*>::iterator it = tmpPrevs.begin(); it != tmpPrevs.end(); ++it) { - it->first->setPixData(it->second, PREVIEW_PIXBUF_WIDTH, VBLOCK); + for (std::map<ColorItem*, cairo_pattern_t*>::iterator it = tmpPrevs.begin(); it != tmpPrevs.end(); ++it) { + it->first->setPattern(it->second); + cairo_pattern_destroy(it->second); } for (std::map<ColorItem*, SPGradient*>::iterator it = tmpGrads.begin(); it != tmpGrads.end(); ++it) { @@ -957,7 +957,6 @@ void SwatchesPanel::handleGradientsChange(SPDocument *document) delete *it; } - // Figure out which SwatchesPanel instances are affected and update them. for (std::map<SwatchesPanel*, SPDocument*>::iterator it = docPerPanel.begin(); it != docPerPanel.end(); ++it) { @@ -978,7 +977,7 @@ void SwatchesPanel::handleDefsModified(SPDocument *document) SwatchPage *docPalette = (docPalettes.find(document) != docPalettes.end()) ? docPalettes[document] : 0; if (docPalette && !DocTrack::queueUpdateIfNeeded(document) ) { std::vector<ColorItem*> tmpColors; - std::map<ColorItem*, guchar*> tmpPrevs; + std::map<ColorItem*, cairo_pattern_t*> tmpPrevs; std::map<ColorItem*, SPGradient*> tmpGrads; recalcSwatchContents(document, tmpColors, tmpPrevs, tmpGrads); @@ -999,10 +998,17 @@ void SwatchesPanel::handleDefsModified(SPDocument *document) oldColor->setGradient(tmpGrads[newColor]); } if ( tmpPrevs.find(newColor) != tmpPrevs.end() ) { - oldColor->setPixData(tmpPrevs[newColor], PREVIEW_PIXBUF_WIDTH, VBLOCK); + oldColor->setPattern(tmpPrevs[newColor]); } } } + + for (std::map<ColorItem*, cairo_pattern_t*>::iterator it = tmpPrevs.begin(); it != tmpPrevs.end(); ++it) { + cairo_pattern_destroy(it->second); + } + for (std::vector<ColorItem*>::iterator it = tmpColors.begin(); it != tmpColors.end(); ++it) { + delete *it; + } } } diff --git a/src/ui/dialog/transformation.cpp b/src/ui/dialog/transformation.cpp index 38664fd3a..901d02240 100644 --- a/src/ui/dialog/transformation.cpp +++ b/src/ui/dialog/transformation.cpp @@ -21,7 +21,6 @@ #include "desktop-handles.h" #include "transformation.h" #include "align-and-distribute.h" -#include "libnr/nr-matrix-ops.h" #include "inkscape.h" #include "selection.h" #include "selection-chemistry.h" diff --git a/src/ui/widget/color-preview.cpp b/src/ui/widget/color-preview.cpp index add596444..a4212c7ba 100644 --- a/src/ui/widget/color-preview.cpp +++ b/src/ui/widget/color-preview.cpp @@ -11,8 +11,8 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "display/nr-plain-stuff-gdk.h" -#include "color-preview.h" +#include "ui/widget/color-preview.h" +#include "display/cairo-utils.h" #define SPCP_DEFAULT_WIDTH 32 #define SPCP_DEFAULT_HEIGHT 12 @@ -76,6 +76,9 @@ ColorPreview::paint (GdkRectangle *area) if (!gdk_rectangle_intersect (area, &warea, &wpaint)) return; + GtkWidget *widget = GTK_WIDGET(this->gobj()); + cairo_t *ct = gdk_cairo_create(widget->window); + /* Transparent area */ w2 = warea.width / 2; @@ -86,11 +89,15 @@ ColorPreview::paint (GdkRectangle *area) carea.height = warea.height; if (gdk_rectangle_intersect (area, &carea, &cpaint)) { - nr_gdk_draw_rgba32_solid (get_window()->gobj(), - get_style()->get_black_gc()->gobj(), - cpaint.x, cpaint.y, - cpaint.width, cpaint.height, - _rgba); + cairo_pattern_t *checkers = ink_cairo_pattern_create_checkerboard(); + + cairo_rectangle(ct, carea.x, carea.y, carea.width, carea.height); + cairo_set_source(ct, checkers); + cairo_fill_preserve(ct); + ink_cairo_set_source_rgba32(ct, _rgba); + cairo_fill(ct); + + cairo_pattern_destroy(checkers); } /* Solid area */ @@ -101,12 +108,12 @@ ColorPreview::paint (GdkRectangle *area) carea.height = warea.height; if (gdk_rectangle_intersect (area, &carea, &cpaint)) { - nr_gdk_draw_rgba32_solid (get_window()->gobj(), - get_style()->get_black_gc()->gobj(), - cpaint.x, cpaint.y, - cpaint.width, cpaint.height, - _rgba | 0xff); + cairo_rectangle(ct, carea.x, carea.y, carea.width, carea.height); + ink_cairo_set_source_rgba32(ct, _rgba | 0xff); + cairo_fill(ct); } + + cairo_destroy(ct); } }}} diff --git a/src/vanishing-point.h b/src/vanishing-point.h index 9fcb6bb46..0551c87ba 100644 --- a/src/vanishing-point.h +++ b/src/vanishing-point.h @@ -67,7 +67,7 @@ public: return persp3d_get_VP (_persp, _axis).is_finite(); } inline Geom::Point get_pos() const { - g_return_val_if_fail (_persp, Geom::Point (NR_HUGE, NR_HUGE)); + g_return_val_if_fail (_persp, Geom::Point (Geom::infinity(), Geom::infinity())); return persp3d_get_VP (_persp,_axis).affine(); } inline Persp3D * get_perspective() const { diff --git a/src/verbs.cpp b/src/verbs.cpp index c332cc93d..1cdbd71d0 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -824,9 +824,6 @@ FileVerb::perform(SPAction *action, void *data, void */*pdata*/) case SP_VERB_FILE_VACUUM: sp_file_vacuum(); break; - case SP_VERB_FILE_PRINT_PREVIEW: - sp_file_print_preview(NULL, NULL); - break; case SP_VERB_FILE_IMPORT: sp_file_import(*parent); break; @@ -2258,8 +2255,6 @@ Verb *Verb::_base_verbs[] = { // TRANSLATORS: "Vacuum Defs" means "Clean up defs" (so as to remove unused definitions) new FileVerb(SP_VERB_FILE_VACUUM, "FileVacuum", N_("Vac_uum Defs"), N_("Remove unused definitions (such as gradients or clipping paths) from the <defs> of the document"), INKSCAPE_ICON_DOCUMENT_CLEANUP ), - new FileVerb(SP_VERB_FILE_PRINT_PREVIEW, "FilePrintPreview", N_("Print Previe_w"), - N_("Preview document printout"), GTK_STOCK_PRINT_PREVIEW ), new FileVerb(SP_VERB_FILE_IMPORT, "FileImport", N_("_Import..."), N_("Import a bitmap or SVG image into this document"), INKSCAPE_ICON_DOCUMENT_IMPORT), new FileVerb(SP_VERB_FILE_EXPORT, "FileExport", N_("_Export Bitmap..."), diff --git a/src/verbs.h b/src/verbs.h index dd5c4db35..5387b57c2 100644 --- a/src/verbs.h +++ b/src/verbs.h @@ -41,7 +41,6 @@ enum { SP_VERB_FILE_SAVE_A_COPY, /**< Save a copy of the current file */ SP_VERB_FILE_PRINT, SP_VERB_FILE_VACUUM, - SP_VERB_FILE_PRINT_PREVIEW, SP_VERB_FILE_IMPORT, SP_VERB_FILE_EXPORT, SP_VERB_FILE_IMPORT_FROM_OCAL, /**< Import the file from Open Clip Art Library */ diff --git a/src/widgets/Makefile_insert b/src/widgets/Makefile_insert index af32ec700..86046b918 100644 --- a/src/widgets/Makefile_insert +++ b/src/widgets/Makefile_insert @@ -42,8 +42,6 @@ ink_common_sources += \ widgets/sp-color-icc-selector.h \ widgets/sp-color-notebook.cpp \ widgets/sp-color-notebook.h \ - widgets/sp-color-preview.cpp \ - widgets/sp-color-preview.h \ widgets/sp-color-scales.cpp \ widgets/sp-color-scales.h \ widgets/sp-color-selector.cpp \ diff --git a/src/widgets/font-selector.cpp b/src/widgets/font-selector.cpp index 8c6afeb4c..965910ba2 100644 --- a/src/widgets/font-selector.cpp +++ b/src/widgets/font-selector.cpp @@ -20,24 +20,24 @@ # include "config.h" #endif -#include <libnr/nr-blit.h> -#include <libnr/nr-convert2geom.h> #include <libnrtype/font-instance.h> -#include <libnrtype/raster-glyph.h> -#include <libnrtype/RasterFont.h> -#include <libnrtype/TextWrapper.h> -#include <libnrtype/one-glyph.h> #include <libnrtype/font-lister.h> #include <2geom/transforms.h> #include <gtk/gtk.h> +#include <gtk/gtkframe.h> +#include <gtk/gtkscrolledwindow.h> +#include <gtk/gtkclist.h> +#include <gtk/gtkvbox.h> +#include <gtk/gtkcombo.h> +#include <gtk/gtkentry.h> +#include <gtk/gtkdrawingarea.h> -#include "../display/nr-plain-stuff-gdk.h" #include <glibmm/i18n.h> -#include "../desktop.h" -#include "font-selector.h" +#include "desktop.h" +#include "widgets/font-selector.h" /* SPFontSelector */ @@ -130,13 +130,12 @@ static void sp_font_selector_class_init(SPFontSelectorClass *c) fs_parent_class = (GtkHBoxClass* )gtk_type_class(GTK_TYPE_HBOX); - fs_signals[FONT_SET] = g_signal_new ("font_set", - G_TYPE_FROM_CLASS(object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET(SPFontSelectorClass, font_set), - NULL, NULL, + fs_signals[FONT_SET] = gtk_signal_new ("font_set", + GTK_RUN_FIRST, + GTK_CLASS_TYPE(object_class), + GTK_SIGNAL_OFFSET(SPFontSelectorClass, font_set), gtk_marshal_NONE__POINTER, - G_TYPE_NONE, + GTK_TYPE_NONE, 1, GTK_TYPE_POINTER); object_class->destroy = sp_font_selector_destroy; @@ -148,10 +147,7 @@ static void sp_font_selector_init(SPFontSelector *fsel) gtk_box_set_spacing(GTK_BOX(fsel), 4); /* Family frame */ - GtkWidget *ft = gtk_label_new_with_mnemonic(_("F_ont family")); - GtkWidget *f = gtk_frame_new(NULL); - gtk_frame_set_label_widget ((GtkFrame*)f, ft); - + GtkWidget *f = gtk_frame_new(_("Font family")); gtk_widget_show (f); gtk_box_pack_start (GTK_BOX(fsel), f, TRUE, TRUE, 0); @@ -175,7 +171,6 @@ static void sp_font_selector_init(SPFontSelector *fsel) gtk_tree_view_set_model (GTK_TREE_VIEW(fsel->family_treeview), GTK_TREE_MODEL (Glib::unwrap (store))); gtk_container_add(GTK_CONTAINER(sw), fsel->family_treeview); gtk_widget_show_all (sw); - gtk_label_set_mnemonic_widget((GtkLabel*)ft, fsel->family_treeview); GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(fsel->family_treeview)); g_signal_connect (G_OBJECT(selection), "changed", G_CALLBACK (sp_font_selector_family_select_row), fsel); @@ -183,9 +178,7 @@ static void sp_font_selector_init(SPFontSelector *fsel) /* Style frame */ - ft = gtk_label_new_with_mnemonic(C_("Font selector", "_Style")); - f = gtk_frame_new(NULL); - gtk_frame_set_label_widget ((GtkFrame*)f, ft); + f = gtk_frame_new(C_("Font selector", "Style")); gtk_widget_show(f); gtk_box_pack_start(GTK_BOX (fsel), f, TRUE, TRUE, 0); @@ -210,7 +203,6 @@ static void sp_font_selector_init(SPFontSelector *fsel) gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(fsel->style_treeview), FALSE); gtk_container_add(GTK_CONTAINER(sw), fsel->style_treeview); gtk_widget_show_all (sw); - gtk_label_set_mnemonic_widget((GtkLabel*)ft, fsel->style_treeview); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(fsel->style_treeview)); g_signal_connect (G_OBJECT(selection), "changed", G_CALLBACK (sp_font_selector_style_select_row), fsel); @@ -224,14 +216,13 @@ static void sp_font_selector_init(SPFontSelector *fsel) g_signal_connect (G_OBJECT(fsel->size), "changed", G_CALLBACK (sp_font_selector_size_changed), fsel); gtk_box_pack_end (GTK_BOX(hb), fsel->size, FALSE, FALSE, 0); - GtkWidget *l = gtk_label_new_with_mnemonic(_("Font si_ze:")); + GtkWidget *l = gtk_label_new(_("Font size:")); gtk_widget_show_all (l); gtk_box_pack_end(GTK_BOX (hb), l, FALSE, FALSE, 0); - gtk_label_set_mnemonic_widget((GtkLabel*)l, fsel->size); for (unsigned int n = 0; sizes[n]; ++n) { - gtk_combo_box_append_text ((GtkComboBox *)fsel->size, sizes[n]); + gtk_combo_box_append_text (GTK_COMBO_BOX(fsel->size), sizes[n]); } gtk_widget_show_all (fsel->size); @@ -389,7 +380,7 @@ static void sp_font_selector_emit_set (SPFontSelector *fsel) fsel->font->Unref(); } fsel->font = font; - g_signal_emit(G_OBJECT(fsel), fs_signals[FONT_SET], 0, fsel->font); + gtk_signal_emit(GTK_OBJECT(fsel), fs_signals[FONT_SET], fsel->font); } fsel->fontsize_dirty = false; if (font) { @@ -521,321 +512,6 @@ double sp_font_selector_get_size(SPFontSelector *fsel) return fsel->fontsize; } -/* SPFontPreview */ - -struct SPFontPreview -{ - GtkDrawingArea darea; - - font_instance *font; - raster_font *rfont; - gchar *phrase; - unsigned long rgba; -}; - -struct SPFontPreviewClass -{ - GtkDrawingAreaClass parent_class; -}; - -static void sp_font_preview_class_init(SPFontPreviewClass *c); -static void sp_font_preview_init(SPFontPreview *fsel); -static void sp_font_preview_destroy(GtkObject *object); - -void sp_font_preview_size_request(GtkWidget *widget, GtkRequisition *req); -static gint sp_font_preview_expose(GtkWidget *widget, GdkEventExpose *event); - -static GtkDrawingAreaClass *fp_parent_class = NULL; - -GType sp_font_preview_get_type() -{ - static GType type = 0; - if (!type) { - GTypeInfo info = { - sizeof(SPFontPreviewClass), - 0, // base_init - 0, // base_finalize - (GClassInitFunc)sp_font_preview_class_init, - 0, // class_finalize - 0, // class_data - sizeof(SPFontPreview), - 0, // n_preallocs - (GInstanceInitFunc)sp_font_preview_init, - 0 // value_table - }; - type = g_type_register_static(GTK_TYPE_DRAWING_AREA, "SPFontPreview", &info, static_cast<GTypeFlags>(0)); - } - return type; -} - -static void sp_font_preview_class_init (SPFontPreviewClass *c) -{ - GtkObjectClass *object_class = (GtkObjectClass *) c; - GtkWidgetClass *widget_class = (GtkWidgetClass *) c; - - fp_parent_class = (GtkDrawingAreaClass*) gtk_type_class(GTK_TYPE_DRAWING_AREA); - - object_class->destroy = sp_font_preview_destroy; - - widget_class->size_request = sp_font_preview_size_request; - widget_class->expose_event = sp_font_preview_expose; -} - -static void sp_font_preview_init(SPFontPreview *fprev) -{ - fprev->rgba = 0x000000ff; -} - -static void sp_font_preview_destroy(GtkObject *object) -{ - SPFontPreview *fprev = SP_FONT_PREVIEW (object); - - if (fprev->rfont) { - fprev->rfont->Unref(); - fprev->rfont = NULL; - } - - if (fprev->font) { - fprev->font->Unref(); - fprev->font = NULL; - } - - g_free(fprev->phrase); - fprev->phrase = NULL; - - if (GTK_OBJECT_CLASS (fp_parent_class)->destroy) { - GTK_OBJECT_CLASS (fp_parent_class)->destroy(object); - } -} - -void sp_font_preview_size_request(GtkWidget */*widget*/, GtkRequisition *req) -{ - req->width = 256; - req->height = 32; -} - -#define SPFP_MAX_LEN 64 - -static gint sp_font_preview_expose(GtkWidget *widget, GdkEventExpose *event) -{ - SPFontPreview *fprev = SP_FONT_PREVIEW(widget); - - if (gtk_widget_is_drawable (widget)) { - if (fprev->rfont) { - - int glyphs[SPFP_MAX_LEN]; - double hpos[SPFP_MAX_LEN]; - - font_instance *tface = fprev->rfont->daddy; - - double theSize = fprev->rfont->style.transform.descrim(); - - gchar const *p; - if (fprev->phrase) { - p = fprev->phrase; - } else { - /* TRANSLATORS: Test string used in text and font dialog (when no - * text has been entered) to get a preview of the font. Choose - * some representative characters that users of your locale will be - * interested in. */ - p = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()"); - } - int len = 0; - - NRRect bbox; - bbox.x0 = bbox.y0 = bbox.x1 = bbox.y1 = 0.0; - - text_wrapper* str_text=new text_wrapper; - str_text->SetDefaultFont(tface); - str_text->AppendUTF8(p,-1); - if ( str_text->uni32_length > 0 ) { - str_text->DoLayout(); - if ( str_text->glyph_length > 0 ) { - PangoFont *curPF = NULL; - font_instance *curF = NULL; - for (int i = 0; i < str_text->glyph_length && i < SPFP_MAX_LEN; i++) { - if ( str_text->glyph_text[i].font != curPF ) { - curPF = str_text->glyph_text[i].font; - if (curF) { - curF->Unref(); - } - curF = NULL; - if ( curPF ) { - PangoFontDescription* pfd = pango_font_describe(curPF); - curF = (font_factory::Default())->Face(pfd); - pango_font_description_free(pfd); - } - } - Geom::Point base_pt(str_text->glyph_text[i].x, str_text->glyph_text[i].y); - base_pt *= theSize; - - glyphs[len] = str_text->glyph_text[i].gl; - hpos[len] = base_pt[0]; - len++; - if ( curF ) { - Geom::OptRect nbbox = curF->BBox(str_text->glyph_text[i].gl); - if (nbbox) { - bbox.x0 = MIN(bbox.x0, base_pt[Geom::X] + theSize * (nbbox->min())[0]); - bbox.y0 = MIN(bbox.y0, base_pt[Geom::Y] - theSize * (nbbox->max())[1]); - bbox.x1 = MAX(bbox.x1, base_pt[Geom::X] + theSize * (nbbox->max())[0]); - bbox.y1 = MAX(bbox.y1, base_pt[Geom::Y] - theSize * (nbbox->min())[1]); - } - } - } - if ( curF ) { - curF->Unref(); - } - } - } - - // XXX: FIXME: why does this code ignore adv.y - /* while (p && *p && (len < SPFP_MAX_LEN)) { - unsigned int unival; - NRRect gbox; - unival = g_utf8_get_char (p); - glyphs[len] = tface->MapUnicodeChar( unival); - hpos[len] = (int)px; - Geom::Point adv = fprev->rfont->Advance(glyphs[len]); - fprev->rfont->BBox( glyphs[len], &gbox); - bbox.x0 = MIN (px + gbox.x0, bbox.x0); - bbox.y0 = MIN (py + gbox.y0, bbox.y0); - bbox.x1 = MAX (px + gbox.x1, bbox.x1); - bbox.y1 = MAX (py + gbox.y1, bbox.y1); - px += adv[Geom::X]; - len += 1; - p = g_utf8_next_char (p); - }*/ - - float startx = (widget->allocation.width - (bbox.x1 - bbox.x0)) / 2; - float starty = widget->allocation.height - (widget->allocation.height - (bbox.y1 - bbox.y0)) / 2 - bbox.y1; - - for (int y = event->area.y; y < event->area.y + event->area.height; y += 64) { - for (int x = event->area.x; x < event->area.x + event->area.width; x += 64) { - NRPixBlock pb, m; - int x0 = x; - int y0 = y; - int x1 = MIN(x0 + 64, event->area.x + event->area.width); - int y1 = MIN(y0 + 64, event->area.y + event->area.height); - guchar *ps = nr_pixelstore_16K_new (TRUE, 0xff); - nr_pixblock_setup_extern(&pb, NR_PIXBLOCK_MODE_R8G8B8, x0, y0, x1, y1, ps, 3 * (x1 - x0), FALSE, FALSE); - nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, x0, y0, x1, y1, TRUE); - pb.empty = FALSE; - - PangoFont *curPF = NULL; - font_instance *curF = NULL; - raster_font *curRF = NULL; - for (int i=0; i < len; i++) { - if ( str_text->glyph_text[i].font != curPF ) { - curPF=str_text->glyph_text[i].font; - if ( curF ) { - curF->Unref(); - } - curF = NULL; - if ( curPF ) { - PangoFontDescription* pfd = pango_font_describe(curPF); - curF=(font_factory::Default())->Face(pfd); - pango_font_description_free(pfd); - } - if ( curF ) { - if ( curRF ) { - curRF->Unref(); - } - curRF = NULL; - curRF = curF->RasterFont(fprev->rfont->style); - } - } - raster_glyph *g = (curRF) ? curRF->GetGlyph(glyphs[i]) : NULL; - if ( g ) { - g->Blit(Geom::Point(hpos[i] + startx, starty), m); - } - } - if (curRF) { - curRF->Unref(); - } - if (curF) { - curF->Unref(); - } - - nr_blit_pixblock_mask_rgba32(&pb, &m, fprev->rgba); - gdk_draw_rgb_image(widget->window, widget->style->black_gc, - x0, y0, x1 - x0, y1 - y0, - GDK_RGB_DITHER_NONE, NR_PIXBLOCK_PX (&pb), pb.rs); - nr_pixblock_release(&m); - nr_pixblock_release(&pb); - nr_pixelstore_16K_free(ps); - } - } - - delete str_text; - - } else { - nr_gdk_draw_gray_garbage(widget->window, widget->style->black_gc, - event->area.x, event->area.y, - event->area.width, event->area.height); - } - } - - return TRUE; -} - -GtkWidget * sp_font_preview_new() -{ - GtkWidget *w = (GtkWidget*) gtk_type_new(SP_TYPE_FONT_PREVIEW); - - return w; -} - -void sp_font_preview_set_font(SPFontPreview *fprev, font_instance *font, SPFontSelector *fsel) -{ - if (font) - { - font->Ref(); - } - - if (fprev->font) - { - fprev->font->Unref(); - } - - fprev->font = font; - - if (fprev->rfont) - { - fprev->rfont->Unref(); - fprev->rfont=NULL; - } - - if (fprev->font) - { - Geom::Affine flip(Geom::Scale(fsel->fontsize, -fsel->fontsize)); - fprev->rfont = fprev->font->RasterFont(flip, 0); - } - - if (gtk_widget_is_drawable (GTK_WIDGET (fprev))) gtk_widget_queue_draw (GTK_WIDGET (fprev)); -} - -void sp_font_preview_set_rgba32(SPFontPreview *fprev, guint32 rgba) -{ - fprev->rgba = rgba; - if (gtk_widget_is_drawable (GTK_WIDGET (fprev))) { - gtk_widget_queue_draw (GTK_WIDGET (fprev)); - } -} - -void sp_font_preview_set_phrase(SPFontPreview *fprev, const gchar *phrase) -{ - g_free (fprev->phrase); - if (phrase) { - fprev->phrase = g_strdup (phrase); - } else { - fprev->phrase = NULL; - } - if (gtk_widget_is_drawable( GTK_WIDGET (fprev))) { - gtk_widget_queue_draw (GTK_WIDGET (fprev)); - } -} - - /* Local Variables: mode:c++ diff --git a/src/widgets/font-selector.h b/src/widgets/font-selector.h index 41a671bae..febd4a34a 100644 --- a/src/widgets/font-selector.h +++ b/src/widgets/font-selector.h @@ -17,18 +17,13 @@ #include <glib.h> struct SPFontSelector; -struct SPFontPreview; #define SP_TYPE_FONT_SELECTOR (sp_font_selector_get_type ()) -#define SP_FONT_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_FONT_SELECTOR, SPFontSelector)) -#define SP_IS_FONT_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_FONT_SELECTOR)) - -#define SP_TYPE_FONT_PREVIEW (sp_font_preview_get_type ()) -#define SP_FONT_PREVIEW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_FONT_PREVIEW, SPFontPreview)) -#define SP_IS_FONT_PREVIEW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_FONT_PREVIEW)) +#define SP_FONT_SELECTOR(o) (GTK_CHECK_CAST ((o), SP_TYPE_FONT_SELECTOR, SPFontSelector)) +#define SP_IS_FONT_SELECTOR(o) (GTK_CHECK_TYPE ((o), SP_TYPE_FONT_SELECTOR)) #include <libnrtype/nrtype-forward.h> -#include <gtk/gtk.h> +#include <gtk/gtkwidget.h> /* SPFontSelector */ @@ -41,16 +36,6 @@ void sp_font_selector_set_font (SPFontSelector *fsel, font_instance *font, doubl font_instance *sp_font_selector_get_font (SPFontSelector *fsel); double sp_font_selector_get_size (SPFontSelector *fsel); -/* SPFontPreview */ - -GtkType sp_font_preview_get_type (void); - -GtkWidget *sp_font_preview_new (void); - -void sp_font_preview_set_font (SPFontPreview *fprev, font_instance *font, SPFontSelector *fsel); -void sp_font_preview_set_rgba32 (SPFontPreview *fprev, guint32 rgba); -void sp_font_preview_set_phrase (SPFontPreview *fprev, const gchar *phrase); - #endif diff --git a/src/widgets/gradient-image.cpp b/src/widgets/gradient-image.cpp index f3a471bfc..ef05ad381 100644 --- a/src/widgets/gradient-image.cpp +++ b/src/widgets/gradient-image.cpp @@ -12,10 +12,8 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <libnr/nr-pixblock-pattern.h> #include "macros.h" -#include "../display/nr-plain-stuff.h" -#include "../display/nr-plain-stuff-gdk.h" +#include "display/cairo-utils.h" #include "gradient-image.h" #include "sp-gradient.h" #include "sp-gradient-fns.h" @@ -29,10 +27,7 @@ static void sp_gradient_image_class_init (SPGradientImageClass *klass); static void sp_gradient_image_init (SPGradientImage *image); static void sp_gradient_image_destroy (GtkObject *object); -static void sp_gradient_image_realize (GtkWidget *widget); -static void sp_gradient_image_unrealize (GtkWidget *widget); static void sp_gradient_image_size_request (GtkWidget *widget, GtkRequisition *requisition); -static void sp_gradient_image_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static gint sp_gradient_image_expose (GtkWidget *widget, GdkEventExpose *event); static void sp_gradient_image_gradient_release (SPObject *, SPGradientImage *im); @@ -76,20 +71,16 @@ sp_gradient_image_class_init (SPGradientImageClass *klass) object_class->destroy = sp_gradient_image_destroy; - widget_class->realize = sp_gradient_image_realize; - widget_class->unrealize = sp_gradient_image_unrealize; widget_class->size_request = sp_gradient_image_size_request; - widget_class->size_allocate = sp_gradient_image_size_allocate; widget_class->expose_event = sp_gradient_image_expose; } static void sp_gradient_image_init (SPGradientImage *image) { - gtk_widget_set_has_window (GTK_WIDGET (image), FALSE); + GTK_WIDGET_SET_FLAGS (image, GTK_NO_WINDOW); image->gradient = NULL; - image->px = NULL; new (&image->release_connection) sigc::connection(); new (&image->modified_connection) sigc::connection(); @@ -116,104 +107,39 @@ sp_gradient_image_destroy (GtkObject *object) } static void -sp_gradient_image_realize (GtkWidget *widget) -{ - SPGradientImage *image; - - image = SP_GRADIENT_IMAGE (widget); - - if (((GtkWidgetClass *) parent_class)->realize) - (* ((GtkWidgetClass *) parent_class)->realize) (widget); - - g_assert (!image->px); - image->px = g_new (guchar, 3 * VBLOCK * widget->allocation.width); - sp_gradient_image_update (image); -} - -static void -sp_gradient_image_unrealize (GtkWidget *widget) -{ - SPGradientImage *image; - - image = SP_GRADIENT_IMAGE (widget); - - if (((GtkWidgetClass *) parent_class)->unrealize) - (* ((GtkWidgetClass *) parent_class)->unrealize) (widget); - - g_assert (image->px); - g_free (image->px); - image->px = NULL; -} - -static void sp_gradient_image_size_request (GtkWidget *widget, GtkRequisition *requisition) { - SPGradientImage *slider; - - slider = SP_GRADIENT_IMAGE (widget); - requisition->width = 64; requisition->height = 12; } -static void -sp_gradient_image_size_allocate (GtkWidget *widget, GtkAllocation *allocation) -{ - SPGradientImage *image; - - image = SP_GRADIENT_IMAGE (widget); - - widget->allocation = *allocation; - - if (gtk_widget_get_realized (widget)) { - g_free (image->px); - image->px = g_new (guchar, 3 * VBLOCK * allocation->width); - } - - sp_gradient_image_update (image); -} - static gint sp_gradient_image_expose (GtkWidget *widget, GdkEventExpose *event) { - SPGradientImage *image; - - image = SP_GRADIENT_IMAGE (widget); - - if (gtk_widget_is_drawable (widget)) { - gint x0, y0, x1, y1; - x0 = MAX (event->area.x, widget->allocation.x); - y0 = MAX (event->area.y, widget->allocation.y); - x1 = MIN (event->area.x + event->area.width, widget->allocation.x + widget->allocation.width); - y1 = MIN (event->area.y + event->area.height, widget->allocation.y + widget->allocation.height); - if ((x1 > x0) && (y1 > y0)) { - if (image->px) { - if (image->gradient) { - gint y; - guchar *p; - p = image->px + 3 * (x0 - widget->allocation.x); - for (y = y0; y < y1; y += VBLOCK) { - gdk_draw_rgb_image (widget->window, widget->style->black_gc, - x0, y, - (x1 - x0), MIN (VBLOCK, y1 - y), - GDK_RGB_DITHER_MAX, - p, widget->allocation.width * 3); - } - } else { - nr_gdk_draw_gray_garbage (widget->window, widget->style->black_gc, - x0, y0, - x1 - x0, y1 - y0); - } - } else { - gdk_draw_rectangle (widget->window, widget->style->black_gc, - x0, y0, - (x1 - x0), (y1 - x0), - TRUE); - } - } - } - - return TRUE; + SPGradientImage *image = SP_GRADIENT_IMAGE (widget); + SPGradient *gr = image->gradient; + + cairo_t *ct = gdk_cairo_create(widget->window); + + cairo_rectangle(ct, event->area.x, event->area.y, + event->area.width, event->area.height); + cairo_clip(ct); + cairo_translate(ct, widget->allocation.x, widget->allocation.y); + + cairo_pattern_t *check = ink_cairo_pattern_create_checkerboard(); + cairo_set_source(ct, check); + cairo_paint(ct); + cairo_pattern_destroy(check); + + if (gr) { + cairo_pattern_t *p = sp_gradient_create_preview_pattern(gr, widget->allocation.width); + cairo_set_source(ct, p); + cairo_paint(ct); + cairo_pattern_destroy(p); + } + cairo_destroy(ct); + + return TRUE; } GtkWidget * @@ -268,27 +194,7 @@ sp_gradient_image_gradient_modified (SPObject *, guint /*flags*/, SPGradientImag static void sp_gradient_image_update (SPGradientImage *image) { - GtkAllocation *allocation; - - if (!image->px) return; - - allocation = &((GtkWidget *) image)->allocation; - - if (image->gradient) { - nr_render_checkerboard_rgb (image->px, allocation->width, VBLOCK, 3 * allocation->width, 0, 0); - sp_gradient_render_vector_block_rgb (image->gradient, - image->px, allocation->width, VBLOCK, 3 * allocation->width, - 0, allocation->width, TRUE); - } else { - NRPixBlock pb; - nr_pixblock_setup_extern (&pb, NR_PIXBLOCK_MODE_R8G8B8, - 0, 0, allocation->width, VBLOCK, - image->px, 3 * allocation->width, TRUE, FALSE); - nr_pixblock_render_gray_noise (&pb, NULL); - nr_pixblock_release (&pb); - } - - if (gtk_widget_is_drawable (GTK_WIDGET (image))) { + if (GTK_WIDGET_DRAWABLE (image)) { gtk_widget_queue_draw (GTK_WIDGET (image)); } } diff --git a/src/widgets/gradient-image.h b/src/widgets/gradient-image.h index 0f911d4ef..ae5d40f56 100644 --- a/src/widgets/gradient-image.h +++ b/src/widgets/gradient-image.h @@ -14,7 +14,7 @@ */ #include <gtk/gtk.h> -#include "../libnr/nr-matrix.h" + class SPGradient; #include <glib.h> @@ -31,7 +31,6 @@ class SPGradient; struct SPGradientImage { GtkWidget widget; SPGradient *gradient; - guchar *px; sigc::connection release_connection; sigc::connection modified_connection; @@ -46,6 +45,4 @@ GtkType sp_gradient_image_get_type (void); GtkWidget *sp_gradient_image_new (SPGradient *gradient); void sp_gradient_image_set_gradient (SPGradientImage *gi, SPGradient *gr); - - #endif diff --git a/src/widgets/gradient-vector.cpp b/src/widgets/gradient-vector.cpp index bc29bc974..a58b22d7c 100644 --- a/src/widgets/gradient-vector.cpp +++ b/src/widgets/gradient-vector.cpp @@ -424,7 +424,7 @@ void SPGradientVectorSelector::setSwatched() ##################################################################*/ #include "../widgets/sp-color-notebook.h" -#include "../widgets/sp-color-preview.h" +#include "ui/widget/color-preview.h" #include "../widgets/widget-sizes.h" #include "../xml/node-event-vector.h" #include "../svg/svg-color.h" @@ -562,7 +562,8 @@ static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_ gtk_widget_show(i); g_object_set_data(G_OBJECT(i), "stop", stop); GtkWidget *hb = gtk_hbox_new(FALSE, 4); - GtkWidget *cpv = sp_color_preview_new(sp_stop_get_rgba32(stop)); + GtkWidget *cpv = GTK_WIDGET(Gtk::manage( + new Inkscape::UI::Widget::ColorPreview(sp_stop_get_rgba32(stop)))->gobj()); gtk_widget_show(cpv); gtk_container_add( GTK_CONTAINER(hb), cpv ); g_object_set_data( G_OBJECT(i), "preview", cpv ); @@ -1188,8 +1189,8 @@ static void sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *o blocked = FALSE; - SPColorPreview *cpv = static_cast<SPColorPreview *>(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "preview")); - sp_color_preview_set_rgba32(cpv, sp_stop_get_rgba32(stop)); + Inkscape::UI::Widget::ColorPreview *cpv = static_cast<Inkscape::UI::Widget::ColorPreview *>(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "preview")); + cpv->setRgba32(sp_stop_get_rgba32(stop)); } /* diff --git a/src/widgets/icon.cpp b/src/widgets/icon.cpp index b1d5c73bb..450c5f0d9 100644 --- a/src/widgets/icon.cpp +++ b/src/widgets/icon.cpp @@ -29,6 +29,7 @@ #include "inkscape.h" #include "document.h" #include "sp-item.h" +#include "display/cairo-utils.h" #include "display/nr-arena.h" #include "display/nr-arena-item.h" #include "io/sys.h" @@ -88,7 +89,7 @@ struct IconImpl { static std::list<gchar*> &icons_svg_paths(); static guchar *load_svg_pixels(std::list<Glib::ustring> const &names, - unsigned lsize, unsigned psize); + unsigned psize, unsigned &stride); static std::string fileEscape( std::string const & str ); @@ -1072,8 +1073,10 @@ GdkPixbuf *IconImpl::loadPixmap(gchar const *name, unsigned /*lsize*/, unsigned } // takes doc, root, icon, and icon name to produce pixels -extern "C" guchar *sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, - gchar const *name, unsigned psize ) +extern "C" guchar * +sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, + gchar const *name, unsigned psize, + unsigned &stride) { bool const dump = Inkscape::Preferences::get()->getBool("/debug/icons/dumpSvg"); guchar *px = NULL; @@ -1174,22 +1177,29 @@ extern "C" guchar *sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, g_message( " area --'%s' (%f,%f)-(%f,%f)", name, (double)area.x0, (double)area.y0, (double)area.x1, (double)area.y1 ); g_message( " ua --'%s' (%f,%f)-(%f,%f)", name, (double)ua.x0, (double)ua.y0, (double)ua.x1, (double)ua.y1 ); } + + stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, psize); + /* Set up pixblock */ - px = g_new(guchar, 4 * psize * psize); - memset(px, 0x00, 4 * psize * psize); + px = g_new(guchar, stride * psize); + memset(px, 0x00, stride * psize); + /* Render */ - NRPixBlock B; - nr_pixblock_setup_extern( &B, NR_PIXBLOCK_MODE_R8G8B8A8N, - ua.x0, ua.y0, ua.x1, ua.y1, - px + 4 * psize * (ua.y0 - area.y0) + - 4 * (ua.x0 - area.x0), - 4 * psize, FALSE, FALSE ); - nr_arena_item_invoke_render(NULL, root, &ua, &B, + cairo_surface_t *s = cairo_image_surface_create_for_data(px, + CAIRO_FORMAT_ARGB32, psize, psize, stride); + cairo_t *ct = cairo_create(s); + cairo_translate(ct, -ua.x0, -ua.y0); + + nr_arena_item_invoke_render(ct, root, &ua, NULL, NR_ARENA_ITEM_RENDER_NO_CACHE ); - nr_pixblock_release(&B); + cairo_destroy(ct); + cairo_surface_destroy(s); + + // convert to GdkPixbuf format + convert_pixels_argb32_to_pixbuf(px, psize, psize, stride); if ( Inkscape::Preferences::get()->getBool("/debug/icons/overlaySvg") ) { - IconImpl::overlayPixels( px, psize, psize, 4 * psize, 0x00, 0x00, 0xff ); + IconImpl::overlayPixels( px, psize, psize, stride, 0x00, 0x00, 0xff ); } } } @@ -1245,7 +1255,7 @@ std::list<gchar*> &IconImpl::icons_svg_paths() // this function renders icons from icons.svg and returns the pixels. guchar *IconImpl::load_svg_pixels(std::list<Glib::ustring> const &names, - unsigned /*lsize*/, unsigned psize) + unsigned psize, unsigned &stride) { bool const dump = Inkscape::Preferences::get()->getBool("/debug/icons/dumpSvg"); std::list<gchar *> &sources = icons_svg_paths(); @@ -1292,7 +1302,7 @@ guchar *IconImpl::load_svg_pixels(std::list<Glib::ustring> const &names, } if (info) { for (std::list<Glib::ustring>::const_iterator it = names.begin(); !px && (it != names.end()); ++it ) { - px = sp_icon_doc_icon( info->doc, info->root, it->c_str(), psize ); + px = sp_icon_doc_icon( info->doc, info->root, it->c_str(), psize, stride ); } } } @@ -1416,10 +1426,11 @@ bool IconImpl::prerenderIcon(gchar const *name, GtkIconSize lsize, unsigned psiz g_message("load_svg_pixels([%s] = %s, %d, %d)", name, legacyNames[name].c_str(), lsize, psize); } } - guchar* px = load_svg_pixels(names, lsize, psize); + unsigned stride; + guchar* px = load_svg_pixels(names, psize, stride); if (px) { GdkPixbuf* pb = gdk_pixbuf_new_from_data( px, GDK_COLORSPACE_RGB, TRUE, 8, - psize, psize, psize * 4, + psize, psize, stride, reinterpret_cast<GdkPixbufDestroyNotify>(g_free), NULL ); pb_cache[key] = pb; addToIconSet(pb, name, lsize, psize); @@ -1457,10 +1468,11 @@ GdkPixbuf *IconImpl::loadSvg(std::list<Glib::ustring> const &names, GtkIconSize // did we already load this icon at this scale/size? GdkPixbuf* pb = get_cached_pixbuf(key); if (!pb) { - guchar *px = load_svg_pixels(names, lsize, psize); + unsigned stride; + guchar *px = load_svg_pixels(names, psize, stride); if (px) { pb = gdk_pixbuf_new_from_data(px, GDK_COLORSPACE_RGB, TRUE, 8, - psize, psize, psize * 4, + psize, psize, stride, (GdkPixbufDestroyNotify)g_free, NULL); pb_cache[key] = pb; addToIconSet(pb, names.begin()->c_str(), lsize, psize); diff --git a/src/widgets/sp-color-preview.cpp b/src/widgets/sp-color-preview.cpp deleted file mode 100644 index 433301f85..000000000 --- a/src/widgets/sp-color-preview.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/* - * A simple color preview widget - * - * Author: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "../display/nr-plain-stuff-gdk.h" -#include "sp-color-preview.h" - -#define SPCP_DEFAULT_WIDTH 32 -#define SPCP_DEFAULT_HEIGHT 11 - -static void sp_color_preview_class_init (SPColorPreviewClass *klass); -static void sp_color_preview_init (SPColorPreview *image); -static void sp_color_preview_destroy (GtkObject *object); - -static void sp_color_preview_size_request (GtkWidget *widget, GtkRequisition *requisition); -static void sp_color_preview_size_allocate (GtkWidget *widget, GtkAllocation *allocation); -static gint sp_color_preview_expose (GtkWidget *widget, GdkEventExpose *event); - -static void sp_color_preview_paint (SPColorPreview *cp, GdkRectangle *area); - -static GtkWidgetClass *parent_class; - -GType sp_color_preview_get_type(void) -{ - static GType type = 0; - if (!type) { - static const GTypeInfo info = { - sizeof(SPColorPreviewClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) sp_color_preview_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(SPColorPreview), - 0, /* n_preallocs */ - (GInstanceInitFunc) sp_color_preview_init, - 0, /* value_table */ - }; - - type = g_type_register_static( GTK_TYPE_WIDGET, - "SPColorPreview", - &info, - static_cast< GTypeFlags > (0) ); - } - return type; -} - -static void -sp_color_preview_class_init (SPColorPreviewClass *klass) -{ - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - object_class = (GtkObjectClass *) klass; - widget_class = (GtkWidgetClass *) klass; - - parent_class = (GtkWidgetClass*)gtk_type_class (GTK_TYPE_WIDGET); - - object_class->destroy = sp_color_preview_destroy; - - widget_class->size_request = sp_color_preview_size_request; - widget_class->size_allocate = sp_color_preview_size_allocate; - widget_class->expose_event = sp_color_preview_expose; -} - -static void -sp_color_preview_init (SPColorPreview *image) -{ - gtk_widget_set_has_window (GTK_WIDGET (image), FALSE); - - image->rgba = 0xffffffff; -} - -static void -sp_color_preview_destroy (GtkObject *object) -{ - SPColorPreview *image; - - image = SP_COLOR_PREVIEW (object); - - if (((GtkObjectClass *) (parent_class))->destroy) - (* ((GtkObjectClass *) (parent_class))->destroy) (object); -} - -static void -sp_color_preview_size_request (GtkWidget *widget, GtkRequisition *requisition) -{ - SPColorPreview *slider; - - slider = SP_COLOR_PREVIEW (widget); - - requisition->width = SPCP_DEFAULT_WIDTH; - requisition->height = SPCP_DEFAULT_HEIGHT; -} - -static void -sp_color_preview_size_allocate (GtkWidget *widget, GtkAllocation *allocation) -{ - SPColorPreview *image; - - image = SP_COLOR_PREVIEW (widget); - - widget->allocation = *allocation; - - if (gtk_widget_is_drawable (GTK_WIDGET (image))) { - gtk_widget_queue_draw (GTK_WIDGET (image)); - } -} - -static gint -sp_color_preview_expose (GtkWidget *widget, GdkEventExpose *event) -{ - SPColorPreview *cp; - - cp = SP_COLOR_PREVIEW (widget); - - if (gtk_widget_is_drawable (widget)) { - sp_color_preview_paint (cp, &event->area); - } - - return TRUE; -} - -GtkWidget * -sp_color_preview_new (guint32 rgba) -{ - SPColorPreview *image; - - image = (SPColorPreview*)gtk_type_new (SP_TYPE_COLOR_PREVIEW); - - sp_color_preview_set_rgba32 (image, rgba); - - return (GtkWidget *) image; -} - -void -sp_color_preview_set_rgba32 (SPColorPreview *cp, guint32 rgba) -{ - cp->rgba = rgba; - - if (gtk_widget_is_drawable (GTK_WIDGET (cp))) { - gtk_widget_queue_draw (GTK_WIDGET (cp)); - } -} - -static void -sp_color_preview_paint (SPColorPreview *cp, GdkRectangle *area) -{ - GtkWidget *widget; - GdkRectangle warea, carea; - GdkRectangle wpaint, cpaint; - gint w2; - - widget = GTK_WIDGET (cp); - - warea.x = widget->allocation.x; - warea.y = widget->allocation.y; - warea.width = widget->allocation.width; - warea.height = widget->allocation.height; - - if (!gdk_rectangle_intersect (area, &warea, &wpaint)) return; - - /* Transparent area */ - - w2 = warea.width / 2; - - carea.x = warea.x; - carea.y = warea.y; - carea.width = w2; - carea.height = warea.height; - - if (gdk_rectangle_intersect (area, &carea, &cpaint)) { - nr_gdk_draw_rgba32_solid (widget->window, widget->style->black_gc, - cpaint.x, cpaint.y, - cpaint.width, cpaint.height, - cp->rgba); - } - - /* Solid area */ - - carea.x = warea.x + w2; - carea.y = warea.y; - carea.width = warea.width - w2; - carea.height = warea.height; - - if (gdk_rectangle_intersect (area, &carea, &cpaint)) { - nr_gdk_draw_rgba32_solid (widget->window, widget->style->black_gc, - cpaint.x, cpaint.y, - cpaint.width, cpaint.height, - cp->rgba | 0xff); - } -} - -/* - 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 : diff --git a/src/widgets/sp-color-preview.h b/src/widgets/sp-color-preview.h deleted file mode 100644 index 43abdf11f..000000000 --- a/src/widgets/sp-color-preview.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef SEEN_COLOR_PREVIEW_H -#define SEEN_COLOR_PREVIEW_H - -/* - * A simple color preview widget - * - * Author: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <gtk/gtk.h> - -#include <glib.h> - - - -#define SP_TYPE_COLOR_PREVIEW (sp_color_preview_get_type ()) -#define SP_COLOR_PREVIEW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_COLOR_PREVIEW, SPColorPreview)) -#define SP_COLOR_PREVIEW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SP_TYPE_COLOR_PREVIEW, SPColorPreviewClass)) -#define SP_IS_COLOR_PREVIEW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_COLOR_PREVIEW)) -#define SP_IS_COLOR_PREVIEW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SP_TYPE_COLOR_PREVIEW)) - -struct SPColorPreview { - GtkWidget widget; - - guint32 rgba; -}; - -struct SPColorPreviewClass { - GtkWidgetClass parent_class; -}; - -GType sp_color_preview_get_type(void); - -GtkWidget *sp_color_preview_new(guint32 rgba); - -void sp_color_preview_set_rgba32(SPColorPreview *cp, guint32 color); - - -#endif // SEEN_COLOR_PREVIEW_H -/* - 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 : diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp index d2b280e44..9da39bac4 100644 --- a/src/widgets/stroke-style.cpp +++ b/src/widgets/stroke-style.cpp @@ -613,7 +613,7 @@ static gboolean stroke_width_set_unit(SPUnitSelector *, gdouble average = stroke_average_width (objects); - if (average == NR_HUGE || average == 0) + if (average == Geom::infinity() || average == 0) return FALSE; a->set_value (100.0 * w / average); diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index 8241f1941..01308104e 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -3454,7 +3454,7 @@ static void box3d_set_button_and_adjustment(Persp3D *persp, gtk_action_set_sensitive(act, TRUE); double angle = persp3d_get_infinite_angle(persp, axis); - if (angle != NR_HUGE) { // FIXME: We should catch this error earlier (don't show the spinbutton at all) + if (angle != Geom::infinity()) { // FIXME: We should catch this error earlier (don't show the spinbutton at all) gtk_adjustment_set_value(adj, box3d_normalize_angle(angle)); } } else { |
