X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fextension%2Finternal%2Fcairo-render-context.cpp;h=18a654e275731310005e360bdc1c76c49a1518c3;hb=9dc68827cbd515262ecb8d5ae8547d9e82c72e00;hp=28d1db9a4abbe185a39f631eb27823cc381d266b;hpb=cbfd098e594052d475bf41ca20bb50ae30aabe68;p=inkscape.git diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index 28d1db9a4..18a654e27 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -1,11 +1,11 @@ -#define __SP_CAIRO_RENDER_CONTEXT_C__ - /** \file * Rendering with Cairo. */ /* * Author: * Miklos Erdelyi + * Jon A. Cruz + * Abhishek Sharma * * Copyright (C) 2006 Miklos Erdelyi * @@ -108,7 +108,7 @@ static cairo_status_t _write_callback(void *closure, const unsigned char *data, CairoRenderContext::CairoRenderContext(CairoRenderer *parent) : _dpi(72), - _pdf_level(0), + _pdf_level(1), _ps_level(1), _eps(false), _is_texttopath(FALSE), @@ -670,6 +670,11 @@ CairoRenderContext::popLayer(void) } TRACE(("mask surface: %f x %f at %i dpi\n", surface_width, surface_height, _dpi )); + // Mask should start black, but it is created white. + cairo_set_source_rgba(mask_ctx->_cr, 0.0, 0.0, 0.0, 1.0); + cairo_rectangle(mask_ctx->_cr, 0, 0, surface_width, surface_height); + cairo_fill(mask_ctx->_cr); + // set rendering mode to normal setRenderMode(RENDER_MODE_NORMAL); @@ -700,19 +705,27 @@ CairoRenderContext::popLayer(void) int stride = cairo_image_surface_get_stride(mask_image); unsigned char *pixels = cairo_image_surface_get_data(mask_image); - // premultiply with opacity // In SVG, the rgb channels as well as the alpha channel is used in masking. // In Cairo, only the alpha channel is used thus requiring this conversion. + // SVG specifies that RGB be converted to alpha using luminance-to-alpha. + // Notes: This calculation assumes linear RGB values. VERIFY COLOR SPACE! + // The incoming pixel values already include alpha, fill-opacity, etc., + // however, opacity must still be applied. TRACE(("premul w/ %f\n", opacity)); - guint8 int_opacity = (guint8)(255 * opacity); + const float coeff_r = 0.2125 / 255.0; + const float coeff_g = 0.7154 / 255.0; + const float coeff_b = 0.0721 / 255.0; for (int row = 0 ; row < height; row++) { unsigned char *row_data = pixels + (row * stride); for (int i = 0 ; i < width; i++) { guint32 *pixel = (guint32 *)row_data + i; - *pixel = ((((*pixel & 0x00ff0000) >> 16) * 13817 + - ((*pixel & 0x0000ff00) >> 8) * 46518 + - ((*pixel & 0x000000ff) ) * 4688) * - int_opacity); + float lum_alpha = (((*pixel & 0x00ff0000) >> 16) * coeff_r + + ((*pixel & 0x0000ff00) >> 8) * coeff_g + + ((*pixel & 0x000000ff) ) * coeff_b ); + // lum_alpha can be slightly greater than 1 due to rounding errors... + // but this should be OK since it doesn't matter what the lower + // six hexadecimal numbers of *pixel are. + *pixel = (guint32)(0xff000000 * lum_alpha * opacity); } } @@ -782,6 +795,9 @@ CairoRenderContext::setupSurface(double width, double height) #ifdef CAIRO_HAS_PDF_SURFACE case CAIRO_SURFACE_TYPE_PDF: surface = cairo_pdf_surface_create_for_stream(Inkscape::Extension::Internal::_write_callback, _stream, width, height); +#if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0)) + cairo_pdf_surface_restrict_to_version(surface, (cairo_pdf_version_t)_pdf_level); +#endif break; #endif #ifdef CAIRO_HAS_PS_SURFACE @@ -791,8 +807,15 @@ CairoRenderContext::setupSurface(double width, double height) return FALSE; } #if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 5, 2)) - cairo_ps_surface_restrict_to_level (surface, (cairo_ps_level_t)_ps_level); - cairo_ps_surface_set_eps (surface, (cairo_bool_t) _eps); + cairo_ps_surface_restrict_to_level(surface, (cairo_ps_level_t)_ps_level); + cairo_ps_surface_set_eps(surface, (cairo_bool_t) _eps); +#endif + // Cairo calculates the bounding box itself, however we want to override this. See Launchpad bug #380501 +#if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 2)) + if (override_bbox) { + cairo_ps_dsc_comment(surface, "%%BoundingBox: 100 100 200 200"); + cairo_ps_dsc_comment(surface, "%%PageBoundingBox: 100 100 200 200"); + } #endif break; #endif @@ -960,14 +983,15 @@ CairoRenderContext::popState(void) g_assert( g_slist_length(_state_stack) > 0 ); } -static bool pattern_hasItemChildren (SPPattern *pat) +static bool pattern_hasItemChildren(SPPattern *pat) { - for (SPObject *child = sp_object_first_child(SP_OBJECT(pat)) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { + bool hasItems = false; + for ( SPObject *child = pat->firstChild() ; child && !hasItems; child = child->getNext() ) { if (SP_IS_ITEM (child)) { - return true; + hasItems = true; } } - return false; + return hasItems; } cairo_pattern_t* @@ -1063,14 +1087,14 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver // create arena and group NRArena *arena = NRArena::create(); - unsigned dkey = sp_item_display_key_new(1); + unsigned dkey = SPItem::display_key_new(1); // show items and render them 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 = sp_object_first_child(SP_OBJECT(pat_i)) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { + for ( SPObject *child = pat_i->firstChild() ; child; child = child->getNext() ) { if (SP_IS_ITEM (child)) { - sp_item_invoke_show (SP_ITEM (child), arena, dkey, SP_ITEM_REFERENCE_FLAGS); + SP_ITEM (child)->invoke_show (arena, dkey, SP_ITEM_REFERENCE_FLAGS); _renderer->renderItem(pattern_ctx, SP_ITEM (child)); } } @@ -1097,9 +1121,9 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver // hide all items 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 = sp_object_first_child(SP_OBJECT(pat_i)) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { + for ( SPObject *child = pat_i->firstChild() ; child; child = child->getNext() ) { if (SP_IS_ITEM (child)) { - sp_item_invoke_hide (SP_ITEM (child), dkey); + SP_ITEM (child)->invoke_hide (dkey); } } break; // do not go further up the chain if children are found @@ -1265,7 +1289,7 @@ CairoRenderContext::_setStrokeStyle(SPStyle const *style, NRRect const *pbox) cairo_set_source_rgba(_cr, rgb[0], rgb[1], rgb[2], alpha); } else { - g_assert( style->fill.isPaintserver() + g_assert( style->stroke.isPaintserver() || SP_IS_GRADIENT(SP_STYLE_STROKE_SERVER(style)) || SP_IS_PATTERN(SP_STYLE_STROKE_SERVER(style)) ); @@ -1477,18 +1501,19 @@ CairoRenderContext::_showGlyphs(cairo_t *cr, PangoFont *font, std::vector::const_iterator it_info = glyphtext.begin() ; it_info != glyphtext.end() ; it_info++) { // skip glyphs which are PANGO_GLYPH_EMPTY (0x0FFFFFFF) // or have the PANGO_GLYPH_UNKNOWN_FLAG (0x10000000) set if (it_info->index == 0x0FFFFFFF || it_info->index & 0x10000000) { TRACE(("INVALID GLYPH found\n")); + g_message("Invalid glyph found, continuing..."); num_invalid_glyphs++; continue; } - glyphs[i - num_invalid_glyphs].index = it_info->index; - glyphs[i - num_invalid_glyphs].x = it_info->x; - glyphs[i - num_invalid_glyphs].y = it_info->y; + glyphs[i].index = it_info->index; + glyphs[i].x = it_info->x; + glyphs[i].y = it_info->y; i++; } @@ -1676,4 +1701,4 @@ _write_callback(void *closure, const unsigned char *data, unsigned int length) fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :