Example #1
0
void cairo_context::add_image(agg::trans_affine const& tr, image_data_rgba8 & data, double opacity)
{
    cairo_pattern pattern(data);
    if (!tr.is_identity())
    {
        double m[6];
        tr.store_to(m);
        cairo_matrix_t cairo_matrix;
        cairo_matrix_init(&cairo_matrix,m[0],m[1],m[2],m[3],m[4],m[5]);
        cairo_matrix_invert(&cairo_matrix);
        pattern.set_matrix(cairo_matrix);
    }
    cairo_save(cairo_.get());
    cairo_set_source(cairo_.get(), const_cast<cairo_pattern_t*>(pattern.pattern()));
    cairo_paint_with_alpha(cairo_.get(), opacity);
    cairo_restore(cairo_.get());
    check_object_status_and_throw_exception(*this);
}
Example #2
0
void
grid_push_named_viewport(grid_context_t *gr, 
                         const char *name, const grid_viewport_t *vp)
{
    double x = unit_to_npc(gr, 'x', vp->x);
    double y = unit_to_npc(gr, 'y', vp->y);
    double w = unit_to_npc(gr, 'x', vp->w);
    double h = unit_to_npc(gr, 'y', vp->h);

    cairo_matrix_t vp_mtx, temp_mtx;
    cairo_matrix_init(&vp_mtx, w, 0, 0, h, x, y);
    cairo_matrix_init(&temp_mtx, w, 0, 0, h, x, y);
    cairo_status_t status = cairo_matrix_invert(&temp_mtx);

    if (status == CAIRO_STATUS_SUCCESS) {
        grid_viewport_node_t *node = new_grid_viewport_node();
        cairo_matrix_multiply(node->npc_to_dev, &vp_mtx, gr->current_node->npc_to_dev);

        if (vp->has_ntv) {
            cairo_matrix_init(node->npc_to_ntv, vp->w_ntv, 0, 0, vp->h_ntv, 
                                                vp->x_ntv, vp->y_ntv);
        } else {
            // inherit native coordinates from parent
            cairo_matrix_multiply(node->npc_to_ntv, 
                                  &vp_mtx, gr->current_node->npc_to_ntv);
        }

        if (name) {
            node->name = malloc(strlen(name) + 1);
            strcpy(node->name, name);
        }

        if (gr->current_node->child) {
            gr->current_node->child->didi = node;
            node->gege = gr->current_node->child;
        }

        gr->current_node->child = node;
        node->parent = gr->current_node;
        gr->current_node = node;
    } else {
        fprintf(stderr, "Warning: can't create singular viewport\n");
    }
}
Example #3
0
static void
_cairo_surface_wrapper_get_inverse_transform (cairo_surface_wrapper_t *wrapper,
					      cairo_matrix_t *m)
{
    cairo_matrix_init_identity (m);

    if (! _cairo_matrix_is_identity (&wrapper->target->device_transform_inverse))
	cairo_matrix_multiply (m, &wrapper->target->device_transform_inverse, m);

    if (! _cairo_matrix_is_identity (&wrapper->transform)) {
	cairo_matrix_t inv;
	cairo_status_t status;

	inv = wrapper->transform;
	status = cairo_matrix_invert (&inv);
	assert (status == CAIRO_STATUS_SUCCESS);
	cairo_matrix_multiply (m, &inv, m);
    }
}
Example #4
0
void
_cairo_surface_wrapper_set_inverse_transform (cairo_surface_wrapper_t *wrapper,
					      const cairo_matrix_t *transform)
{
    cairo_status_t status;

    if (transform == NULL || _cairo_matrix_is_identity (transform)) {
	cairo_matrix_init_identity (&wrapper->transform);

	wrapper->needs_transform =
	    _cairo_surface_wrapper_needs_device_transform (wrapper);
    } else {
	wrapper->transform = *transform;
	status = cairo_matrix_invert (&wrapper->transform);
	/* should always be invertible unless given pathological input */
	assert (status == CAIRO_STATUS_SUCCESS);

	wrapper->needs_transform = TRUE;
    }
}
Example #5
0
static void
swfdec_text_render (SwfdecGraphic *graphic, cairo_t *cr, 
    const SwfdecColorTransform *trans)
{
  guint i;
  SwfdecColor color;
  SwfdecText *text = SWFDEC_TEXT (graphic);
  SwfdecColorTransform force_color;

  cairo_transform (cr, &text->transform);
  /* scale by bounds */
  for (i = 0; i < text->glyphs->len; i++) {
    SwfdecTextGlyph *glyph;
    SwfdecDraw *draw;
    cairo_matrix_t pos;

    glyph = &g_array_index (text->glyphs, SwfdecTextGlyph, i);

    draw = swfdec_font_get_glyph (glyph->font, glyph->glyph);
    if (draw == NULL) {
      SWFDEC_INFO ("failed getting glyph %d, maybe an empty glyph?", glyph->glyph);
      continue;
    }

    cairo_matrix_init_translate (&pos,
	glyph->x, glyph->y);
    cairo_matrix_scale (&pos, 
	(double) glyph->height / glyph->font->scale_factor,
	(double) glyph->height / glyph->font->scale_factor);
    cairo_save (cr);
    cairo_transform (cr, &pos);
    if (!cairo_matrix_invert (&pos)) {
      color = swfdec_color_apply_transform (glyph->color, trans);
      swfdec_color_transform_init_color (&force_color, color);
      swfdec_draw_paint (draw, cr, &force_color);
    } else {
      SWFDEC_ERROR ("non-invertible matrix!");
    }
    cairo_restore (cr);
  }
}
static cairo_int_status_t
_cairo_type3_glyph_surface_show_glyphs (void		     *abstract_surface,
					cairo_operator_t      op,
					cairo_pattern_t	     *source,
					cairo_glyph_t        *glyphs,
					int		      num_glyphs,
					cairo_scaled_font_t  *scaled_font,
					int		     *remaining_glyphs)
{
    cairo_type3_glyph_surface_t *surface = abstract_surface;
    cairo_int_status_t status;
    cairo_scaled_font_t *font;
    cairo_matrix_t new_ctm, ctm_inverse;
    int i;

    for (i = 0; i < num_glyphs; i++)
	cairo_matrix_transform_point (&surface->cairo_to_pdf, &glyphs[i].x, &glyphs[i].y);

    /* We require the matrix to be invertable. */
    ctm_inverse = scaled_font->ctm;
    status = cairo_matrix_invert (&ctm_inverse);
    if (status)
	return CAIRO_INT_STATUS_IMAGE_FALLBACK;

    cairo_matrix_multiply (&new_ctm, &scaled_font->ctm, &ctm_inverse);
    font = cairo_scaled_font_create (scaled_font->font_face,
				     &scaled_font->font_matrix,
				     &new_ctm,
				     &scaled_font->options);

    status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
						    NULL, 0,
						    glyphs, num_glyphs,
						    NULL, 0,
						    FALSE,
						    font);

    cairo_scaled_font_destroy (font);

    return status;
}
Example #7
0
/* This routine invokes the point method of the item.  The argument x, y
 * should be in the parent's item-relative coordinate system.  This routine
 * applies the inverse of the item's transform, maintaining the affine
 * invariant. */
static GnomeCanvasItem *
gnome_canvas_item_invoke_point (GnomeCanvasItem *item,
                                gdouble x,
                                gdouble y,
                                gint cx,
                                gint cy)
{
	cairo_matrix_t inverse;

	/* Calculate x & y in item local coordinates */
	inverse = item->matrix;
	if (cairo_matrix_invert (&inverse) != CAIRO_STATUS_SUCCESS)
		return NULL;

	cairo_matrix_transform_point (&inverse, &x, &y);

	if (GNOME_CANVAS_ITEM_GET_CLASS (item)->point)
		return GNOME_CANVAS_ITEM_GET_CLASS (item)->point (item, x, y, cx, cy);

	return NULL;
}
Example #8
0
wxSVGRect wxSVGCanvasPathCairo::GetResultBBox(const wxCSSStyleDeclaration& style, const wxSVGMatrix* matrix) {
	if (matrix) {
		cairo_matrix_t m;
		cairo_matrix_init(&m, matrix->GetA(), matrix->GetB(), matrix->GetC(), matrix->GetD(),
				matrix->GetE(), matrix->GetF());
		cairo_matrix_invert(&m);
		cairo_set_matrix(m_cr, &m);
	}
	ApplyStrokeStyle(m_cr, style);
	double x1, y1, x2, y2;
	if (style.GetStrokeWidth() > 0)
		cairo_stroke_extents(m_cr, &x1, &y1, &x2, &y2);
	else
		cairo_fill_extents(m_cr, &x1, &y1, &x2, &y2);
	if (matrix) {
		cairo_matrix_t mat;
		cairo_matrix_init(&mat, 1, 0, 0, 1, 0, 0);
		cairo_set_matrix(m_cr, &mat);
	}
	return wxSVGRect(x1, y1, x2 - x1, y2 - y1);
}
Example #9
0
static cairo_status_t
test_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
			       unsigned long         glyph,
			       cairo_t              *cr,
			       cairo_text_extents_t *metrics)
{
    test_scaled_font_glyph_t *glyphs = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
								      &test_font_face_glyphs_key);
    int i;
    unsigned char *data;
    cairo_surface_t *image;
    cairo_pattern_t *pattern;
    cairo_matrix_t matrix;
    uint8_t byte;

    /* FIXME: We simply crash on out-of-bound glyph indices */

    metrics->x_advance = (glyphs[glyph].width + 1) / 8.0;

    image = cairo_image_surface_create (CAIRO_FORMAT_A1, glyphs[glyph].width, 8);
    data = cairo_image_surface_get_data (image);
    for (i = 0; i < 8; i++) {
	byte = glyphs[glyph].data[i];
	*data = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (byte);
	data += cairo_image_surface_get_stride (image);
    }

    pattern = cairo_pattern_create_for_surface (image);
    cairo_matrix_init_identity (&matrix);
    cairo_matrix_scale (&matrix, 1.0/8.0, 1.0/8.0);
    cairo_matrix_translate (&matrix, 0, -8);
    cairo_matrix_invert (&matrix);
    cairo_pattern_set_matrix (pattern, &matrix);
    cairo_set_source (cr, pattern);
    cairo_mask (cr, pattern);
    cairo_pattern_destroy (pattern);
    cairo_surface_destroy (image);

    return CAIRO_STATUS_SUCCESS;
}
cairo_pattern_t* Gradient::platformGradient(float globalAlpha)
{
    if (m_gradient && m_platformGradientAlpha == globalAlpha)
        return m_gradient;

    platformDestroy();
    m_platformGradientAlpha = globalAlpha;

    if (m_radial)
        m_gradient = cairo_pattern_create_radial(m_p0.x(), m_p0.y(), m_r0, m_p1.x(), m_p1.y(), m_r1);
    else
        m_gradient = cairo_pattern_create_linear(m_p0.x(), m_p0.y(), m_p1.x(), m_p1.y());

    Vector<ColorStop>::iterator stopIterator = m_stops.begin();
    while (stopIterator != m_stops.end()) {
        cairo_pattern_add_color_stop_rgba(m_gradient, stopIterator->stop,
                                          stopIterator->red, stopIterator->green, stopIterator->blue,
                                          stopIterator->alpha * globalAlpha);
        ++stopIterator;
    }

    switch (m_spreadMethod) {
    case SpreadMethodPad:
        cairo_pattern_set_extend(m_gradient, CAIRO_EXTEND_PAD);
        break;
    case SpreadMethodReflect:
        cairo_pattern_set_extend(m_gradient, CAIRO_EXTEND_REFLECT);
        break;
    case SpreadMethodRepeat:
        cairo_pattern_set_extend(m_gradient, CAIRO_EXTEND_REPEAT);
        break;
    }

    cairo_matrix_t matrix = m_gradientSpaceTransformation;
    cairo_matrix_invert(&matrix);
    cairo_pattern_set_matrix(m_gradient, &matrix);

    return m_gradient;
}
Example #11
0
cairo_status_t
_cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
			     cairo_operator_t	 op,
			     const cairo_pattern_t *source,
			     const cairo_pattern_t *mask,
			     const cairo_clip_t	    *clip)
{
    cairo_status_t status;
    cairo_clip_t *dev_clip;
    cairo_pattern_union_t source_copy;
    cairo_pattern_union_t mask_copy;

    if (unlikely (wrapper->target->status))
	return wrapper->target->status;

    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
    if (_cairo_clip_is_all_clipped (dev_clip))
	return (cairo_status_t)CAIRO_INT_STATUS_NOTHING_TO_DO;

    if (wrapper->needs_transform) {
	cairo_matrix_t m;

	_cairo_surface_wrapper_get_transform (wrapper, &m);

	status = cairo_matrix_invert (&m);
	assert (status == CAIRO_STATUS_SUCCESS);

	_copy_transformed_pattern (&source_copy.base, source, &m);
	source = &source_copy.base;

	_copy_transformed_pattern (&mask_copy.base, mask, &m);
	mask = &mask_copy.base;
    }

    status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip);

    _cairo_clip_destroy (dev_clip);
    return status;
}
void QCairoPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s)
{
    double w, h;
    cairo_surface_t *image;
    QImage img=pixmap.toImage().convertToFormat(QImage::Format_ARGB32);


    if (!img.isNull()) {
        cairo_format_t imgformat=CAIRO_FORMAT_ARGB32;

        updateMatrix();

        image = cairo_image_surface_create_for_data(img.bits(), imgformat, img.width(), img.height(), img.bytesPerLine());
        w = img.width();
        h = img.height();

        cairo_matrix_t cm;
        cairo_matrix_init_identity(&cm);
        cairo_matrix_translate (&cm, s.x(), s.y());
        cairo_matrix_invert(&cm);

        cairo_pattern_t* brush=cairo_pattern_create_for_surface(image);
        cairo_pattern_set_matrix(brush, &cm);
        cairo_pattern_set_extend(brush, CAIRO_EXTEND_REPEAT);

        cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height());
        cairo_set_source(cr, brush);
        cairo_fill_preserve(cr);
        cairo_set_source_rgba(cr, 0,0,0,0);
        cairo_set_line_width(cr, 0.0);
        cairo_stroke(cr);
        //cairo_fill(cr);

        //cairo_set_source_surface (cr, image, 0, 0);
        //cairo_paint(cr);
        releasePattern(brush);
        updateMatrix();
    }
}
Example #13
0
void cgDrawImage(cairo_t *cr, int x, int y, int width, int height, cairo_surface_t *img_surface, int img_w, int img_h) {
    if (img_surface && img_w>0 && img_h>0 && width>0 && height>0) {
        cairo_save(cr);
            cairo_matrix_t cm;
            cairo_matrix_init_identity(&cm);
            cairo_matrix_translate (&cm, x, y);
            if (width!=img_w || height!=img_h) cairo_matrix_scale(&cm, float(width)/float(img_w), float(height)/float(img_h));
            cairo_matrix_invert(&cm);

            cairo_pattern_t* brush=cairo_pattern_create_for_surface(img_surface);
            cairo_pattern_set_matrix(brush, &cm);
            cairo_pattern_set_extend(brush, CAIRO_EXTEND_NONE);

            cairo_rectangle(cr, x, y, width, height);
            cairo_set_source(cr, brush);
            cairo_fill_preserve(cr);
            cairo_set_source_rgba(cr, 0,0,0,0);
            cairo_set_line_width(cr, 0.0);
            cairo_stroke(cr);
            cairo_pattern_destroy(brush);
        cairo_restore(cr);
    }
}
Example #14
0
static gboolean
_adg_get_map(GtkWidget *widget, gboolean local_space,
             cairo_matrix_t *map, cairo_matrix_t *inverted)
{
    AdgGtkAreaPrivate *data = adg_gtk_area_get_instance_private((AdgGtkArea *) widget);
    AdgEntity *entity = (AdgEntity *) data->canvas;

    if (entity == NULL)
        return FALSE;

    if (local_space) {
        adg_matrix_copy(map, adg_entity_get_local_map(entity));

        /* The inverted map is subject to the global matrix */
        adg_matrix_copy(inverted, adg_entity_get_global_matrix(entity));
        adg_matrix_transform(inverted, map, ADG_TRANSFORM_BEFORE);
    } else {
        adg_matrix_copy(map, adg_entity_get_global_map(entity));
        adg_matrix_copy(inverted, map);
    }

    return cairo_matrix_invert(inverted) == CAIRO_STATUS_SUCCESS;
}
Example #15
0
void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSize& imageSize, const FloatRect& tileRect,
                               const AffineTransform& patternTransform, const FloatPoint& phase, cairo_operator_t op, const FloatRect& destRect)
{
    // Avoid NaN
    if (!isfinite(phase.x()) || !isfinite(phase.y()))
       return;

    cairo_save(cr);

    RefPtr<cairo_surface_t> clippedImageSurface = 0;
    if (tileRect.size() != imageSize) {
        IntRect imageRect = enclosingIntRect(tileRect);
        clippedImageSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, imageRect.width(), imageRect.height()));
        RefPtr<cairo_t> clippedImageContext = adoptRef(cairo_create(clippedImageSurface.get()));
        cairo_set_source_surface(clippedImageContext.get(), image, -tileRect.x(), -tileRect.y());
        cairo_paint(clippedImageContext.get());
        image = clippedImageSurface.get();
    }

    cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image);
    cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);

    cairo_matrix_t patternMatrix = cairo_matrix_t(patternTransform);
    cairo_matrix_t phaseMatrix = {1, 0, 0, 1, phase.x() + tileRect.x() * patternTransform.a(), phase.y() + tileRect.y() * patternTransform.d()};
    cairo_matrix_t combined;
    cairo_matrix_multiply(&combined, &patternMatrix, &phaseMatrix);
    cairo_matrix_invert(&combined);
    cairo_pattern_set_matrix(pattern, &combined);

    cairo_set_operator(cr, op);
    cairo_set_source(cr, pattern);
    cairo_pattern_destroy(pattern);
    cairo_rectangle(cr, destRect.x(), destRect.y(), destRect.width(), destRect.height());
    cairo_fill(cr);

    cairo_restore(cr);
}
Example #16
0
void
gimp_display_shell_rotate_update_transform (GimpDisplayShell *shell)
{
  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));

  g_free (shell->rotate_transform);
  g_free (shell->rotate_untransform);

  if (shell->rotate_angle != 0.0 && gimp_display_get_image (shell->display))
    {
      gint    image_width, image_height;
      gdouble cx, cy;

      shell->rotate_transform   = g_new (cairo_matrix_t, 1);
      shell->rotate_untransform = g_new (cairo_matrix_t, 1);

      gimp_display_shell_scale_get_image_size (shell,
                                               &image_width, &image_height);

      cx = -shell->offset_x + image_width  / 2;
      cy = -shell->offset_y + image_height / 2;

      cairo_matrix_init_translate (shell->rotate_transform, cx, cy);
      cairo_matrix_rotate (shell->rotate_transform,
                           shell->rotate_angle / 180.0 * G_PI);
      cairo_matrix_translate (shell->rotate_transform, -cx, -cy);

      *shell->rotate_untransform = *shell->rotate_transform;
      cairo_matrix_invert (shell->rotate_untransform);
    }
  else
    {
      shell->rotate_transform   = NULL;
      shell->rotate_untransform = NULL;
    }
}
cairo_status_t
_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
				    cairo_operator_t	     fill_op,
				    const cairo_pattern_t   *fill_source,
				    cairo_fill_rule_t	     fill_rule,
				    double		     fill_tolerance,
				    cairo_antialias_t	     fill_antialias,
				    cairo_path_fixed_t	    *path,
				    cairo_operator_t	     stroke_op,
				    const cairo_pattern_t   *stroke_source,
				    cairo_stroke_style_t    *stroke_style,
				    cairo_matrix_t	    *stroke_ctm,
				    cairo_matrix_t	    *stroke_ctm_inverse,
				    double		     stroke_tolerance,
				    cairo_antialias_t	     stroke_antialias,
				    cairo_clip_t	    *clip)
{
    cairo_status_t status;
    cairo_matrix_t device_transform;
    cairo_path_fixed_t path_copy, *dev_path = path;
    cairo_clip_t clip_copy, *dev_clip = clip;
    cairo_matrix_t dev_ctm = *stroke_ctm;
    cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;

    if (unlikely (wrapper->target->status))
	return wrapper->target->status;

    if (clip && clip->all_clipped)
	return CAIRO_STATUS_SUCCESS;

    if (_cairo_surface_wrapper_needs_device_transform (wrapper,
						       &device_transform))
    {
	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
	if (unlikely (status))
	    goto FINISH;

	_cairo_path_fixed_transform (&path_copy, &device_transform);
	dev_path = &path_copy;

	if (clip != NULL) {
	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
							&device_transform);
	    if (unlikely (status))
		goto FINISH;

	    dev_clip = &clip_copy;
	}

	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &device_transform);
	status = cairo_matrix_invert (&device_transform);
	assert (status == CAIRO_STATUS_SUCCESS);
	cairo_matrix_multiply (&dev_ctm_inverse,
			       &device_transform,
			       &dev_ctm_inverse);
    } else {
	if (clip != NULL) {
	    dev_clip = &clip_copy;
	    _cairo_clip_init_copy (&clip_copy, clip);
	}
    }

    status = _cairo_surface_fill_stroke (wrapper->target,
					 fill_op, fill_source, fill_rule,
					 fill_tolerance, fill_antialias,
					 dev_path,
					 stroke_op, stroke_source,
					 stroke_style,
					 &dev_ctm, &dev_ctm_inverse,
					 stroke_tolerance, stroke_antialias,
					 dev_clip);

  FINISH:
    if (dev_path != path)
	_cairo_path_fixed_fini (dev_path);
    if (dev_clip != clip)
	_cairo_clip_reset (dev_clip);
    return status;
}
Example #18
0
static void
brush_end_element (GMarkupParseContext  *context,
                   const gchar          *element_name,
                   gpointer              user_data,
                   GError              **error)
{
        GXPSBrush *brush = (GXPSBrush *)user_data;

        if (strcmp (element_name, "SolidColorBrush") == 0) {
        } else if (strcmp (element_name, "LinearGradientBrush") == 0) {
                g_markup_parse_context_pop (context);
        } else if (strcmp (element_name, "RadialGradientBrush") == 0) {
                g_markup_parse_context_pop (context);
        } else if (strcmp (element_name, "ImageBrush") == 0) {
                GXPSBrushImage  *brush_image;
                GXPSImage       *image;
                GError          *err = NULL;

                brush_image = g_markup_parse_context_pop (context);

                GXPS_DEBUG (g_message ("set_fill_pattern (image)"));
                image = gxps_page_get_image (brush->ctx->page, brush_image->image_uri, &err);
                if (image) {
                        cairo_matrix_t   matrix;
                        gdouble          x_scale, y_scale;
                        cairo_surface_t *clip_surface;

                        /* viewbox units is 1/96 inch, convert to pixels */
                        brush_image->viewbox.x *= image->res_x / 96;
                        brush_image->viewbox.y *= image->res_y / 96;
                        brush_image->viewbox.width *= image->res_x / 96;
                        brush_image->viewbox.height *= image->res_y / 96;

                        clip_surface = cairo_surface_create_for_rectangle (image->surface,
                                                                           brush_image->viewbox.x,
                                                                           brush_image->viewbox.y,
                                                                           brush_image->viewbox.width,
                                                                           brush_image->viewbox.height);
                        brush_image->brush->pattern = cairo_pattern_create_for_surface (clip_surface);
                        cairo_pattern_set_extend (brush_image->brush->pattern, brush_image->extend);

                        x_scale = brush_image->viewport.width / brush_image->viewbox.width;
                        y_scale = brush_image->viewport.height / brush_image->viewbox.height;
                        cairo_matrix_init (&matrix, x_scale, 0, 0, y_scale,
                                           brush_image->viewport.x, brush_image->viewport.y);
                        cairo_matrix_multiply (&matrix, &matrix, &brush_image->matrix);
                        cairo_matrix_invert (&matrix);
                        cairo_pattern_set_matrix (brush_image->brush->pattern, &matrix);

                        if (brush->opacity != 1.0) {
                                cairo_push_group (brush->ctx->cr);
                                cairo_set_source (brush->ctx->cr, brush_image->brush->pattern);
                                cairo_pattern_destroy (brush_image->brush->pattern);
                                cairo_paint_with_alpha (brush->ctx->cr, brush->opacity);
                                brush_image->brush->pattern = cairo_pop_group (brush->ctx->cr);
                        }

                        if (cairo_pattern_status (brush_image->brush->pattern)) {
                                GXPS_DEBUG (g_debug ("%s", cairo_status_to_string (cairo_pattern_status (brush_image->brush->pattern))));
                                cairo_pattern_destroy (brush_image->brush->pattern);
                                brush_image->brush->pattern = NULL;
                        }
                        cairo_surface_destroy (clip_surface);
                } else if (err) {
                        GXPS_DEBUG (g_debug ("%s", err->message));
                        g_error_free (err);
                }
                gxps_brush_image_free (brush_image);
        } else if (strcmp (element_name, "VisualBrush") == 0) {
                GXPSRenderContext *sub_ctx;
                GXPSBrushVisual   *visual;
                cairo_matrix_t     matrix;

                sub_ctx = g_markup_parse_context_pop (context);
                visual = sub_ctx->visual;
                g_slice_free (GXPSRenderContext, sub_ctx);

                GXPS_DEBUG (g_message ("set_fill_pattern (visual)"));
                visual->brush->pattern = cairo_pop_group (brush->ctx->cr);
                /* Undo the clip */
                cairo_restore (brush->ctx->cr);
                cairo_pattern_set_extend (visual->brush->pattern, visual->extend);
                cairo_pattern_get_matrix (visual->brush->pattern, &matrix);
                cairo_matrix_multiply (&matrix, &visual->matrix, &matrix);
                cairo_pattern_set_matrix (visual->brush->pattern, &matrix);
                if (cairo_pattern_status (visual->brush->pattern)) {
                        GXPS_DEBUG (g_debug ("%s", cairo_status_to_string (cairo_pattern_status (visual->brush->pattern))));
                        cairo_pattern_destroy (visual->brush->pattern);
                        visual->brush->pattern = NULL;
                }

                gxps_brush_visual_free (visual);
        } else {
                gxps_parse_error (context,
                                  brush->ctx->page->priv->source,
                                  G_MARKUP_ERROR_UNKNOWN_ELEMENT,
                                  element_name, NULL, NULL, error);

        }
}
Example #19
0
static void
brush_start_element (GMarkupParseContext  *context,
                     const gchar          *element_name,
                     const gchar         **names,
                     const gchar         **values,
                     gpointer              user_data,
                     GError              **error)
{
        GXPSBrush *brush = (GXPSBrush *)user_data;

        if (strcmp (element_name, "SolidColorBrush") == 0) {
                const gchar *color_str = NULL;
                gint i;

                for (i = 0; names[i] != NULL; i++) {
                        if (strcmp (names[i], "Color") == 0) {
                                color_str = values[i];
                        } else if (strcmp (names[i], "Opacity") == 0) {
                                if (!gxps_value_get_double (values[i], &brush->opacity)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "SolidColorBrush", "Opacity",
                                                          values[i], error);
                                        return;
                                }
                        } else {
                                gxps_parse_error (context,
                                                  brush->ctx->page->priv->source,
                                                  G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
                                                  "SolidColorBrush", names[i],
                                                  NULL, error);
                                return;
                        }
                }

                if (!color_str) {
                        gxps_parse_error (context,
                                          brush->ctx->page->priv->source,
                                          G_MARKUP_ERROR_MISSING_ATTRIBUTE,
                                          "SolidColorBrush", "Color",
                                          NULL, error);
                        return;
                }

                GXPS_DEBUG (g_message ("set_fill_pattern (solid)"));
                if (!gxps_brush_solid_color_parse (color_str, brush->ctx->page->priv->zip,
                                                   brush->opacity, &brush->pattern)) {
                        gxps_parse_error (context,
                                          brush->ctx->page->priv->source,
                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                          "SolidColorBrush", "Color",
                                          color_str, error);
                        return;
                }
        } else if (strcmp (element_name, "ImageBrush") == 0) {
                GXPSBrushImage *image;
                gchar *image_source = NULL;
                cairo_rectangle_t viewport = { 0, }, viewbox = { 0, };
                cairo_matrix_t matrix;
                cairo_extend_t extend = CAIRO_EXTEND_NONE;
                gint i;

                cairo_matrix_init_identity (&matrix);

                for (i = 0; names[i] != NULL; i++) {
                        if (strcmp (names[i], "ImageSource") == 0) {
                                image_source = gxps_resolve_relative_path (brush->ctx->page->priv->source,
                                                                           values[i]);
                        } else if (strcmp (names[i], "Transform") == 0) {
                                if (!gxps_matrix_parse (values[i], &matrix)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "ImageBrush", "Transform",
                                                          values[i], error);
                                        return;
                                }
                        } else if (strcmp (names[i], "Viewport") == 0) {
                                if (!gxps_box_parse (values[i], &viewport)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "ImageBrush", "Viewport",
                                                          values[i], error);
                                        return;
                                }
                        } else if (strcmp (names[i], "ViewportUnits") == 0) {
                        } else if (strcmp (names[i], "Viewbox") == 0) {
                                if (!gxps_box_parse (values[i], &viewbox)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "ImageBrush", "Viewbox",
                                                          values[i], error);
                                        return;
                                }
                        } else if (strcmp (names[i], "ViewboxUnits") == 0) {
                        } else if (strcmp (names[i], "TileMode") == 0) {
                                extend = gxps_tile_mode_parse (values[i]);
                        } else if (strcmp (names[i], "Opacity") == 0) {
                                if (!gxps_value_get_double (values[i], &brush->opacity)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "ImageBrush", "Opacity",
                                                          values[i], error);
                                        return;
                                }
                        } else  {
                                gxps_parse_error (context,
                                                  brush->ctx->page->priv->source,
                                                  G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
                                                  "ImageBrush", names[i],
                                                  NULL, error);
                                return;
                        }

                }

                if (!image_source) {
                        gxps_parse_error (context,
                                          brush->ctx->page->priv->source,
                                          G_MARKUP_ERROR_MISSING_ATTRIBUTE,
                                          element_name, "ImageSource",
                                          NULL, error);
                        return;
                }

                /* GXPSBrushImage takes ownership of image_source */
                image = gxps_brush_image_new (brush, image_source, &viewport, &viewbox);
                image->extend = extend;
                image->matrix = matrix;
                g_markup_parse_context_push (context, &brush_image_parser, image);
        } else if (strcmp (element_name, "LinearGradientBrush") == 0) {
                gint           i;
                gdouble        x0, y0, x1, y1;
                cairo_extend_t extend = CAIRO_EXTEND_PAD;
                cairo_matrix_t matrix;

                x0 = y0 = x1 = y1 = -1;
                cairo_matrix_init_identity (&matrix);

                for (i = 0; names[i] != NULL; i++) {
                        if (strcmp (names[i], "MappingMode") == 0) {
                        } else if (strcmp (names[i], "StartPoint") == 0) {
                                if (!gxps_point_parse (values[i], &x0, &y0)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "LinearGradientBrush", "StartPoint",
                                                          values[i], error);
                                        return;
                                }
                        } else if (strcmp (names[i], "EndPoint") == 0) {
                                if (!gxps_point_parse (values[i], &x1, &y1)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "LinearGradientBrush", "EndPoint",
                                                          values[i], error);
                                        return;
                                }
                        } else if (strcmp (names[i], "SpreadMethod") == 0) {
                                extend = gxps_spread_method_parse (values[i]);
                        } else if (strcmp (names[i], "Opacity") == 0) {
                                if (!gxps_value_get_double (values[i], &brush->opacity)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "LinearGradientBrush", "Opacity",
                                                          values[i], error);
                                        return;
                                }
                        } else if (strcmp (names[i], "Transform") == 0) {
                                if (!gxps_matrix_parse (values[i], &matrix)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "LinearGradientBrush", "Transform",
                                                          values[i], error);
                                        return;
                                }
                        } else if (strcmp (names[i], "ColorInterpolationMode") == 0) {
                                GXPS_DEBUG (g_debug ("Unsupported %s attribute: ColorInterpolationMode", element_name));
                        } else {
                                gxps_parse_error (context,
                                                  brush->ctx->page->priv->source,
                                                  G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
                                                  element_name, names[i],
                                                  NULL, error);
                                return;
                        }
                }

                if (x0 == -1 || y0 == -1 || x1 == -1 || y1 == -1) {
                        gxps_parse_error (context,
                                          brush->ctx->page->priv->source,
                                          G_MARKUP_ERROR_MISSING_ATTRIBUTE,
                                          element_name,
                                          (x0 == -1 || y0 == -1) ? "StartPoint" : "EndPoint",
                                          NULL, error);
                        return;
                }

                GXPS_DEBUG (g_message ("set_fill_pattern (linear)"));
                brush->pattern = cairo_pattern_create_linear (x0, y0, x1, y1);
                cairo_pattern_set_matrix (brush->pattern, &matrix);
                cairo_pattern_set_extend (brush->pattern, extend);
                g_markup_parse_context_push (context, &brush_gradient_parser, brush);
        } else if (strcmp (element_name, "RadialGradientBrush") == 0) {
                gint           i;
                gdouble        cx0, cy0, r0, cx1, cy1, r1;
                cairo_extend_t extend = CAIRO_EXTEND_PAD;
                cairo_matrix_t matrix;

                cx0 = cy0 = r0 = cx1 = cy1 = r1 = -1;

                cairo_matrix_init_identity (&matrix);

                for (i = 0; names[i] != NULL; i++) {
                        if (strcmp (names[i], "MappingMode") == 0) {
                        } else if (strcmp (names[i], "GradientOrigin") == 0) {
                                if (!gxps_point_parse (values[i], &cx0, &cy0)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "RadialGradientBrush", "GradientOrigin",
                                                          values[i], error);
                                        return;
                                }
                        } else if (strcmp (names[i], "Center") == 0) {
                                if (!gxps_point_parse (values[i], &cx1, &cy1)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "RadialGradientBrush", "Center",
                                                          values[i], error);
                                        return;
                                }
                        } else if (strcmp (names[i], "RadiusX") == 0) {
                                if (!gxps_value_get_double (values[i], &r0)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "RadialGradientBrush", "RadiusX",
                                                          values[i], error);
                                        return;
                                }
                        } else if (strcmp (names[i], "RadiusY") == 0) {
                                if (!gxps_value_get_double (values[i], &r1)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "RadialGradientBrush", "RadiusY",
                                                          values[i], error);
                                        return;
                                }
                        } else if (strcmp (names[i], "SpreadMethod") == 0) {
                                extend = gxps_spread_method_parse (values[i]);
                        } else if (strcmp (names[i], "Opacity") == 0) {
                                if (!gxps_value_get_double (values[i], &brush->opacity)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "RadialGradientBrush", "Opacity",
                                                          values[i], error);
                                        return;
                                }
                        } else if (strcmp (names[i], "Transform") == 0) {
                                if (!gxps_matrix_parse (values[i], &matrix)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "RadialGradientBrush", "Transform",
                                                          values[i], error);
                                        return;
                                }
                        } else if (strcmp (names[i], "ColorInterpolationMode") == 0) {
                                GXPS_DEBUG (g_debug ("Unsupported %s attribute: ColorInterpolationMode", element_name));
                        } else {
                                gxps_parse_error (context,
                                                  brush->ctx->page->priv->source,
                                                  G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
                                                  element_name, names[i],
                                                  NULL, error);
                                return;
                        }
                }

                if (cx0 == -1 || cy0 == -1 || cx1 == -1 || cy1 == -1) {
                        gxps_parse_error (context,
                                          brush->ctx->page->priv->source,
                                          G_MARKUP_ERROR_MISSING_ATTRIBUTE,
                                          element_name,
                                          (cx0 == -1 || cy0 == -1) ? "GradientOrigin" : "Center",
                                          NULL, error);
                        return;
                }
                if (r0 == -1 || r1 == -1) {
                        gxps_parse_error (context,
                                          brush->ctx->page->priv->source,
                                          G_MARKUP_ERROR_MISSING_ATTRIBUTE,
                                          element_name,
                                          (r0 == -1) ? "RadiusX" : "RadiusY",
                                          NULL, error);
                        return;
                }

                GXPS_DEBUG (g_message ("set_fill_pattern (radial)"));
                brush->pattern = cairo_pattern_create_radial (cx0, cy0, 0, cx1, cy1, r1);
                cairo_pattern_set_matrix (brush->pattern, &matrix);
                cairo_pattern_set_extend (brush->pattern, extend);
                g_markup_parse_context_push (context, &brush_gradient_parser, brush);
        } else if (strcmp (element_name, "VisualBrush") == 0) {
                GXPSBrushVisual *visual;
                GXPSRenderContext *sub_ctx;
                cairo_rectangle_t viewport = { 0, }, viewbox = { 0, };
                cairo_matrix_t matrix;
                cairo_extend_t extend = CAIRO_EXTEND_NONE;
                double width, height;
                gint i;

                cairo_matrix_init_identity (&matrix);

                for (i = 0; names[i] != NULL; i++) {
                        if (strcmp (names[i], "TileMode") == 0) {
                                extend = gxps_tile_mode_parse (values[i]);
                        } else if (strcmp (names[i], "Transform") == 0) {
                                if (!gxps_matrix_parse (values[i], &matrix)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "VisualBrush", "Transform",
                                                          values[i], error);
                                        return;
                                }
                        } else if (strcmp (names[i], "Viewport") == 0) {
                                if (!gxps_box_parse (values[i], &viewport)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "VisualBrush", "Viewport",
                                                          values[i], error);
                                        return;
                                }
                        } else if (strcmp (names[i], "ViewportUnits") == 0) {
                        } else if (strcmp (names[i], "Viewbox") == 0) {
                                if (!gxps_box_parse (values[i], &viewbox)) {
                                        gxps_parse_error (context,
                                                          brush->ctx->page->priv->source,
                                                          G_MARKUP_ERROR_INVALID_CONTENT,
                                                          "VisualBrush", "Viewbox",
                                                          values[i], error);
                                        return;
                                }
                        } else if (strcmp (names[i], "ViewboxUnits") == 0) {
                        } else if (strcmp (names[i], "Opacity") == 0) {
                                GXPS_DEBUG (g_debug ("Unsupported %s attribute: Opacity", element_name));
                        } else if (strcmp (names[i], "Visual") == 0) {
                                GXPS_DEBUG (g_debug ("Unsupported %s attribute: Visual", element_name));
                        } else {
                                gxps_parse_error (context,
                                                  brush->ctx->page->priv->source,
                                                  G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
                                                  element_name, names[i],
                                                  NULL, error);
                                return;
                        }
                }

                /* TODO: check required values */

                width = gxps_transform_hypot (&matrix, viewport.width, 0);
                height = gxps_transform_hypot (&matrix, 0, viewport.height);

                cairo_save (brush->ctx->cr);
                cairo_rectangle (brush->ctx->cr, 0, 0, width, height);
                cairo_clip (brush->ctx->cr);
                cairo_push_group (brush->ctx->cr);
                cairo_translate (brush->ctx->cr, -viewbox.x, -viewbox.y);
                cairo_scale (brush->ctx->cr, width / viewbox.width, height / viewbox.height);
                visual = gxps_brush_visual_new (brush, &viewport, &viewbox);
                visual->extend = extend;
                cairo_matrix_init (&visual->matrix, viewport.width / width, 0, 0,
                                   viewport.height / height, viewport.x, viewport.y);
                cairo_matrix_multiply (&visual->matrix, &visual->matrix, &matrix);
                cairo_matrix_invert (&visual->matrix);
                sub_ctx = g_slice_new0 (GXPSRenderContext);
                sub_ctx->page = brush->ctx->page;
                sub_ctx->cr = brush->ctx->cr;
                sub_ctx->visual = visual;
                gxps_page_render_parser_push (context, sub_ctx);
        } else {
                gxps_parse_error (context,
                                  brush->ctx->page->priv->source,
                                  G_MARKUP_ERROR_UNKNOWN_ELEMENT,
                                  element_name, NULL, NULL, error);
        }
}
bool SVGPaintServerGradient::setup(GraphicsContext*& context, const RenderObject* object, SVGPaintTargetType type, bool isPaintingText) const
{
    m_ownerElement->buildGradient();

    cairo_t* cr = context->platformContext();
    cairo_pattern_t* pattern;

    cairo_matrix_t matrix;
    cairo_matrix_init_identity (&matrix);
    const cairo_matrix_t gradient_matrix = gradientTransform();

    if (this->type() == LinearGradientPaintServer) {
        const SVGPaintServerLinearGradient* linear = static_cast<const SVGPaintServerLinearGradient*>(this);

        if (boundingBoxMode()) {
            FloatRect bbox = object->relativeBBox(false);
            cairo_matrix_translate(&matrix, bbox.x(), bbox.y());
            cairo_matrix_scale(&matrix, bbox.width(), bbox.height());
        }

        double x0 = linear->gradientStart().x();
        double y0 = linear->gradientStart().y();
        double x1 = linear->gradientEnd().x();
        double y1 = linear->gradientEnd().y();

        pattern = cairo_pattern_create_linear(x0, y0, x1, y1);

    } else if (this->type() == RadialGradientPaintServer) {
        const SVGPaintServerRadialGradient* radial = static_cast<const SVGPaintServerRadialGradient*>(this);

        if (boundingBoxMode()) {
            FloatRect bbox = object->relativeBBox(false);
            cairo_matrix_translate(&matrix, bbox.x(), bbox.y());
            cairo_matrix_scale(&matrix, bbox.width(), bbox.height());
        }

        double cx = radial->gradientCenter().x();
        double cy = radial->gradientCenter().y();
        double radius = radial->gradientRadius();
        double fx = radial->gradientFocal().x();
        double fy = radial->gradientFocal().y();

        fx -= cx;
        fy -= cy;
        double fradius = 0.0;

        if (sqrt(fx * fx + fy * fy) > radius) {
            double angle = atan2(fy, fx);
            if ((fx + cx) < cx)
                fx = int(cos(angle) * radius) + 1;
            else
                fx = int(cos(angle) * radius) - 1;
            if ((fy + cy) < cy)
                fy = int(sin(angle) * radius) + 1;
            else
                fy = int(sin(angle) * radius) - 1;
        }

        pattern = cairo_pattern_create_radial(fx + cx, fy + cy, fradius, cx, cy, radius);

    } else {
        return false;
    }

    cairo_pattern_set_filter(pattern, CAIRO_FILTER_BILINEAR);

    switch (spreadMethod()) {
        case SPREADMETHOD_PAD:
            cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
            break;
        case SPREADMETHOD_REFLECT:
            cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REFLECT);
            break;
        case SPREADMETHOD_REPEAT:
            cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
            break;
        default:
            cairo_pattern_set_extend(pattern, CAIRO_EXTEND_NONE);
            break;
    }

    cairo_matrix_multiply(&matrix, &matrix, &gradient_matrix);
    cairo_matrix_invert(&matrix);
    cairo_pattern_set_matrix(pattern, &matrix);

    const Vector<SVGGradientStop>& stops = gradientStops();

    for (unsigned i = 0; i < stops.size(); ++i) {
        float offset = stops[i].first;
        Color color = stops[i].second;

        cairo_pattern_add_color_stop_rgba(pattern, offset, color.red() / 255.0, color.green() / 255.0, color.blue() / 255.0, color.alpha() / 255.0);
    }

    cairo_set_source(cr, pattern);
    cairo_pattern_destroy(pattern);

    return true;
}
Example #21
0
cairo_status_t
_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
					 cairo_operator_t	     op,
					 const cairo_pattern_t	    *source,
					 const char		    *utf8,
					 int			     utf8_len,
					 const cairo_glyph_t	    *glyphs,
					 int			     num_glyphs,
					 const cairo_text_cluster_t *clusters,
					 int			     num_clusters,
					 cairo_text_cluster_flags_t  cluster_flags,
					 cairo_scaled_font_t	    *scaled_font,
					 const cairo_clip_t	    *clip)
{
    cairo_status_t status;
    cairo_clip_t *dev_clip;
    cairo_glyph_t stack_glyphs [CAIRO_STACK_ARRAY_LENGTH(cairo_glyph_t)];
    cairo_glyph_t *dev_glyphs = stack_glyphs;
    cairo_scaled_font_t *dev_scaled_font = scaled_font;
    cairo_pattern_union_t source_copy;
    cairo_font_options_t options;

    if (unlikely (wrapper->target->status))
	return wrapper->target->status;

    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
    if (_cairo_clip_is_all_clipped (dev_clip))
	return CAIRO_INT_STATUS_NOTHING_TO_DO;

    cairo_surface_get_font_options (wrapper->target, &options);
    cairo_font_options_merge (&options, &scaled_font->options);

    if (wrapper->needs_transform) {
	cairo_matrix_t m;
	int i;

	_cairo_surface_wrapper_get_transform (wrapper, &m);

	if (! _cairo_matrix_is_translation (&wrapper->transform)) {
	    cairo_matrix_t ctm;

	    /* XXX No device-transform? A bug in the tangle of layers? */
	    _cairo_matrix_multiply (&ctm,
				    &wrapper->transform,
				    &scaled_font->ctm);
	    dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face,
							&scaled_font->font_matrix,
							&ctm, &options);
	}

	if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) {
	    dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
	    if (unlikely (dev_glyphs == NULL)) {
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
		goto FINISH;
	    }
	}

	for (i = 0; i < num_glyphs; i++) {
	    dev_glyphs[i] = glyphs[i];
	    cairo_matrix_transform_point (&m,
					  &dev_glyphs[i].x,
					  &dev_glyphs[i].y);
	}

	status = cairo_matrix_invert (&m);
	assert (status == CAIRO_STATUS_SUCCESS);

	_copy_transformed_pattern (&source_copy.base, source, &m);
	source = &source_copy.base;
    } else {
	if (! cairo_font_options_equal (&options, &scaled_font->options)) {
	    dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face,
							&scaled_font->font_matrix,
							&scaled_font->ctm,
							&options);
	}

	/* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
	 * to modify the glyph array that's passed in.  We must always
	 * copy the array before handing it to the backend.
	 */
	if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) {
	    dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
	    if (unlikely (dev_glyphs == NULL)) {
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
		goto FINISH;
	    }
	}

	memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
    }

    status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
					      utf8, utf8_len,
					      dev_glyphs, num_glyphs,
					      clusters, num_clusters,
					      cluster_flags,
					      dev_scaled_font,
					      dev_clip);
 FINISH:
    _cairo_clip_destroy (dev_clip);
    if (dev_glyphs != stack_glyphs)
	free (dev_glyphs);
    if (dev_scaled_font != scaled_font)
	cairo_scaled_font_destroy (dev_scaled_font);
    return status;
}
cairo_int_status_t
_cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t	  *pdf_operators,
				       const char                 *utf8,
				       int                         utf8_len,
				       cairo_glyph_t              *glyphs,
				       int                         num_glyphs,
				       const cairo_text_cluster_t *clusters,
				       int                         num_clusters,
				       cairo_text_cluster_flags_t  cluster_flags,
				       cairo_scaled_font_t	  *scaled_font)
{
    cairo_status_t status;
    int i;
    cairo_matrix_t text_matrix, invert_y_axis;
    double x, y;
    const char *cur_text;
    cairo_glyph_t *cur_glyph;

    pdf_operators->font_matrix_inverse = scaled_font->font_matrix;
    status = cairo_matrix_invert (&pdf_operators->font_matrix_inverse);
    if (status == CAIRO_STATUS_INVALID_MATRIX)
	return CAIRO_STATUS_SUCCESS;
    assert (status == CAIRO_STATUS_SUCCESS);

    pdf_operators->is_new_text_object = FALSE;
    if (pdf_operators->in_text_object == FALSE) {
	status = _cairo_pdf_operators_begin_text (pdf_operators);
	if (unlikely (status))
	    return status;

	/* Force Tm and Tf to be emitted when starting a new text
	 * object.*/
	pdf_operators->is_new_text_object = TRUE;
    }

    cairo_matrix_init_scale (&invert_y_axis, 1, -1);
    text_matrix = scaled_font->scale;

    /* Invert y axis in font space  */
    cairo_matrix_multiply (&text_matrix, &text_matrix, &invert_y_axis);

    /* Invert y axis in device space  */
    cairo_matrix_multiply (&text_matrix, &invert_y_axis, &text_matrix);

    if (pdf_operators->is_new_text_object ||
	! _cairo_matrix_scale_equal (&pdf_operators->text_matrix, &text_matrix))
    {
	status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
	if (unlikely (status))
	    return status;

	x = glyphs[0].x;
	y = glyphs[0].y;
	cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y);
	text_matrix.x0 = x;
	text_matrix.y0 = y;
	status = _cairo_pdf_operators_set_text_matrix (pdf_operators, &text_matrix);
	if (status == CAIRO_STATUS_INVALID_MATRIX)
	    return CAIRO_STATUS_SUCCESS;
	if (unlikely (status))
	    return status;
    }

    if (num_clusters > 0) {
	cur_text = utf8;
	if ((cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD))
	    cur_glyph = glyphs + num_glyphs;
	else
	    cur_glyph = glyphs;
	for (i = 0; i < num_clusters; i++) {
	    if ((cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD))
		cur_glyph -= clusters[i].num_glyphs;
	    status = _cairo_pdf_operators_emit_cluster (pdf_operators,
							cur_text,
							clusters[i].num_bytes,
							cur_glyph,
							clusters[i].num_glyphs,
							cluster_flags,
							scaled_font);
	    if (unlikely (status))
		return status;

	    cur_text += clusters[i].num_bytes;
	    if (!(cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD))
		cur_glyph += clusters[i].num_glyphs;
	}
    } else {
	for (i = 0; i < num_glyphs; i++) {
	    status = _cairo_pdf_operators_emit_cluster (pdf_operators,
							NULL,
							-1, /* no unicode string available */
							&glyphs[i],
							1,
							FALSE,
							scaled_font);
	    if (unlikely (status))
		return status;
	}
    }

    return _cairo_output_stream_get_status (pdf_operators->stream);
}
Example #23
0
int32_t	Matrix::invert()
{
	return static_cast<int32_t>( cairo_matrix_invert( &getCairoMatrix() ) );
}
Example #24
0
static cairo_status_t
_cairo_matrix_to_pixman_matrix (const cairo_matrix_t	*matrix,
				pixman_transform_t	*pixman_transform,
				double xc,
				double yc)
{
    cairo_matrix_t inv;
    unsigned max_iterations;

    pixman_transform->matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx);
    pixman_transform->matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy);
    pixman_transform->matrix[0][2] = _cairo_fixed_16_16_from_double (matrix->x0);

    pixman_transform->matrix[1][0] = _cairo_fixed_16_16_from_double (matrix->yx);
    pixman_transform->matrix[1][1] = _cairo_fixed_16_16_from_double (matrix->yy);
    pixman_transform->matrix[1][2] = _cairo_fixed_16_16_from_double (matrix->y0);

    pixman_transform->matrix[2][0] = 0;
    pixman_transform->matrix[2][1] = 0;
    pixman_transform->matrix[2][2] = 1 << 16;

    /* The conversion above breaks cairo's translation invariance:
     * a translation of (a, b) in device space translates to
     * a translation of (xx * a + xy * b, yx * a + yy * b)
     * for cairo, while pixman uses rounded versions of xx ... yy.
     * This error increases as a and b get larger.
     *
     * To compensate for this, we fix the point (xc, yc) in pattern
     * space and adjust pixman's transform to agree with cairo's at
     * that point.
     */

    if (_cairo_matrix_has_unity_scale (matrix))
	return CAIRO_STATUS_SUCCESS;

    if (unlikely (fabs (matrix->xx) > PIXMAN_MAX_INT ||
		  fabs (matrix->xy) > PIXMAN_MAX_INT ||
		  fabs (matrix->x0) > PIXMAN_MAX_INT ||
		  fabs (matrix->yx) > PIXMAN_MAX_INT ||
		  fabs (matrix->yy) > PIXMAN_MAX_INT ||
		  fabs (matrix->y0) > PIXMAN_MAX_INT))
    {
	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
    }

    /* Note: If we can't invert the transformation, skip the adjustment. */
    inv = *matrix;
    if (cairo_matrix_invert (&inv) != CAIRO_STATUS_SUCCESS)
	return CAIRO_STATUS_SUCCESS;

    /* find the pattern space coordinate that maps to (xc, yc) */
    max_iterations = 5;
    do {
	double x,y;
	pixman_vector_t vector;
	cairo_fixed_16_16_t dx, dy;

	vector.vector[0] = _cairo_fixed_16_16_from_double (xc);
	vector.vector[1] = _cairo_fixed_16_16_from_double (yc);
	vector.vector[2] = 1 << 16;

	/* If we can't transform the reference point, skip the adjustment. */
	if (! pixman_transform_point_3d (pixman_transform, &vector))
	    return CAIRO_STATUS_SUCCESS;

	x = pixman_fixed_to_double (vector.vector[0]);
	y = pixman_fixed_to_double (vector.vector[1]);
	cairo_matrix_transform_point (&inv, &x, &y);

	/* Ideally, the vector should now be (xc, yc).
	 * We can now compensate for the resulting error.
	 */
	x -= xc;
	y -= yc;
	cairo_matrix_transform_distance (matrix, &x, &y);
	dx = _cairo_fixed_16_16_from_double (x);
	dy = _cairo_fixed_16_16_from_double (y);
	pixman_transform->matrix[0][2] -= dx;
	pixman_transform->matrix[1][2] -= dy;

	if (dx == 0 && dy == 0)
	    return CAIRO_STATUS_SUCCESS;
    } while (--max_iterations);

    /* We didn't find an exact match between cairo and pixman, but
     * the matrix should be mostly correct */
    return CAIRO_STATUS_SUCCESS;
}
Example #25
0
static void _scrollbar_handle_expose(
    struct _scrollbar *self, int x, int y, int w, int h, int count)
{
    cairo_t *cr;
    cairo_matrix_t cm;
    mume_resobj_brush_t *br;
    mume_rect_t r, ru;
    struct _scrollbar_theme *theme;

    if (count > 0)
        return;

    theme = mume_objdesc_cast(
                mume_resmgr_get_object(mume_resmgr(), "scrollbar", "theme"),
                mume_typeof_scrollbar_theme());

    if (NULL == theme) {
        mume_warning(("Get scrollbar theme failed\n"));
        return;
    }

    mume_remove_flag(self->flags, _SCROLLBAR_FLAG_INVALID);

    cr = mume_window_begin_paint(self, MUME_PM_INVALID);
    if (NULL == cr) {
        mume_warning(("Begin paint failed\n"));
        return;
    }

    ru = mume_current_invalid_rect();

    /* Background */
    if (_scrollbar_is_horz(self)) {
        mume_window_get_geometry(
            self, NULL, NULL, &r.height, &r.width);
    }
    else {
        mume_window_get_geometry(
            self, NULL, NULL, &r.width, &r.height);
    }

    cm = _scrollbar_get_matrix(self, r.width, r.height);

    cairo_transform(cr, &cm);

    if (mume_scrollbar_is_scrollable(self))
        br = &theme->bkgnd.normal;
    else
        br = &theme->bkgnd.disabled;

    mume_draw_resobj_brush(
        cr, br, 0, 0, r.width, r.height);

    cairo_matrix_invert(&cm);
    cairo_transform(cr, &cm);

    /* Button1. */
    r = _scrollbar_get_rect(self, MUME_SBHT_BUTTON1);
    if (!mume_rect_is_empty(r) &&
            !mume_rect_is_empty(mume_rect_intersect(ru, r)))
    {
        if (_scrollbar_is_horz(self))
            SWAP(r.width, r.height);

        cm = _scrollbar_get_matrix(self, r.width, r.height);

        cairo_translate(cr, r.x, r.y);
        cairo_transform(cr, &cm);

        if (mume_test_flag(self->flags, _SCROLLBAR_FLAG_TOP) ||
                mume_test_flag(self->flags, _SCROLLBAR_FLAG_RIGHT))
        {
            br = _scrollbar_choose_brush(
                     self, &theme->button1, MUME_SBHT_BUTTON1);
        }
        else {
            br = _scrollbar_choose_brush(
                     self, &theme->button2, MUME_SBHT_BUTTON1);
        }

        mume_draw_resobj_brush(
            cr, br, 0, 0, r.width, r.height);

        cairo_matrix_invert(&cm);
        cairo_transform(cr, &cm);
        cairo_translate(cr, -r.x, -r.y);
    }

    /* Button2. */
    r = _scrollbar_get_rect(self, MUME_SBHT_BUTTON2);
    if (!mume_rect_is_empty(r) &&
            !mume_rect_is_empty(mume_rect_intersect(ru, r)))
    {
        if (_scrollbar_is_horz(self))
            SWAP(r.width, r.height);

        cm = _scrollbar_get_matrix(self, r.width, r.height);

        cairo_translate(cr, r.x, r.y);
        cairo_transform(cr, &cm);

        if (mume_test_flag(self->flags, _SCROLLBAR_FLAG_TOP) ||
                mume_test_flag(self->flags, _SCROLLBAR_FLAG_RIGHT))
        {
            br = _scrollbar_choose_brush(
                     self, &theme->button2, MUME_SBHT_BUTTON2);
        }
        else {
            br = _scrollbar_choose_brush(
                     self, &theme->button1, MUME_SBHT_BUTTON2);
        }

        mume_draw_resobj_brush(
            cr, br, 0, 0, r.width, r.height);

        cairo_matrix_invert(&cm);
        cairo_transform(cr, &cm);
        cairo_translate(cr, -r.x, -r.y);
    }

    /* Thumb. */
    r = _scrollbar_get_rect(self, MUME_SBHT_THUMB);
    if (!mume_rect_is_empty(r) &&
            !mume_rect_is_empty(mume_rect_intersect(ru, r)))
    {
        if (_scrollbar_is_horz(self))
            SWAP(r.width, r.height);

        cm = _scrollbar_get_matrix(self, r.width, r.height);

        cairo_translate(cr, r.x, r.y);
        cairo_transform(cr, &cm);

        br = _scrollbar_choose_brush(
                 self, &theme->thumb, MUME_SBHT_THUMB);

        mume_draw_resobj_brush(
            cr, br, 0, 0, r.width, r.height);

        cairo_matrix_invert(&cm);
        cairo_transform(cr, &cm);
        cairo_translate(cr, -r.x, -r.y);
    }

    mume_window_end_paint(self, cr);
}
Example #26
0
void
_cairo_matrix_to_pixman_matrix (const cairo_matrix_t	*matrix,
				pixman_transform_t	*pixman_transform)
{
    static const pixman_transform_t pixman_identity_transform = {{
        {1 << 16,        0,       0},
        {       0, 1 << 16,       0},
        {       0,       0, 1 << 16}
    }};

    if (_cairo_matrix_is_identity (matrix)) {
        *pixman_transform = pixman_identity_transform;
    }
    else {
        cairo_matrix_t inv = *matrix;
        double x = 0, y = 0;
        pixman_vector_t vector;

        pixman_transform->matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx);
        pixman_transform->matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy);
        pixman_transform->matrix[0][2] = _cairo_fixed_16_16_from_double (matrix->x0);

        pixman_transform->matrix[1][0] = _cairo_fixed_16_16_from_double (matrix->yx);
        pixman_transform->matrix[1][1] = _cairo_fixed_16_16_from_double (matrix->yy);
        pixman_transform->matrix[1][2] = _cairo_fixed_16_16_from_double (matrix->y0);

        pixman_transform->matrix[2][0] = 0;
        pixman_transform->matrix[2][1] = 0;
        pixman_transform->matrix[2][2] = 1 << 16;

        /* The conversion above breaks cairo's translation invariance:
         * a translation of (a, b) in device space translates to
         * a translation of (xx * a + xy * b, yx * a + yy * b)
         * for cairo, while pixman uses rounded versions of xx ... yy.
         * This error increases as a and b get larger.
         *
         * To compensate for this, we fix the point (0, 0) in pattern
         * space and adjust pixman's transform to agree with cairo's at
         * that point. */

        /* Note: If we can't invert the transformation, skip the adjustment. */
        if (cairo_matrix_invert (&inv) != CAIRO_STATUS_SUCCESS)
            return;

        /* find the device space coordinate that maps to (0, 0) */
        cairo_matrix_transform_point (&inv, &x, &y);

        /* transform the resulting device space coordinate back
         * to the pattern space, using pixman's transform */
        vector.vector[0] = _cairo_fixed_16_16_from_double (x);
        vector.vector[1] = _cairo_fixed_16_16_from_double (y);
        vector.vector[2] = 1 << 16;

        if (!pixman_transform_point_3d (pixman_transform, &vector))
            return;

        /* Ideally, the vector should now be (0, 0). We can now compensate
         * for the resulting error */
        pixman_transform->matrix[0][2] -= vector.vector[0];
        pixman_transform->matrix[1][2] -= vector.vector[1];
    }
}
Example #27
0
cairo_status_t
_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
				    cairo_operator_t	     fill_op,
				    const cairo_pattern_t   *fill_source,
				    cairo_fill_rule_t	     fill_rule,
				    double		     fill_tolerance,
				    cairo_antialias_t	     fill_antialias,
				    const cairo_path_fixed_t*path,
				    cairo_operator_t	     stroke_op,
				    const cairo_pattern_t   *stroke_source,
				    const cairo_stroke_style_t    *stroke_style,
				    const cairo_matrix_t	    *stroke_ctm,
				    const cairo_matrix_t	    *stroke_ctm_inverse,
				    double		     stroke_tolerance,
				    cairo_antialias_t	     stroke_antialias,
				    const cairo_clip_t	    *clip)
{
    cairo_status_t status;
    cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *)path;
    cairo_matrix_t dev_ctm = *stroke_ctm;
    cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
    cairo_clip_t *dev_clip;
    cairo_pattern_union_t stroke_source_copy;
    cairo_pattern_union_t fill_source_copy;

    if (unlikely (wrapper->target->status))
	return wrapper->target->status;

    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
    if (_cairo_clip_is_all_clipped (dev_clip))
	return CAIRO_INT_STATUS_NOTHING_TO_DO;

    if (wrapper->needs_transform) {
	cairo_matrix_t m;

	_cairo_surface_wrapper_get_transform (wrapper, &m);

	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
	if (unlikely (status))
	    goto FINISH;

	_cairo_path_fixed_transform (&path_copy, &m);
	dev_path = &path_copy;

	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);

	status = cairo_matrix_invert (&m);
	assert (status == CAIRO_STATUS_SUCCESS);

	cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);

	_copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m);
	stroke_source = &stroke_source_copy.base;

	_copy_transformed_pattern (&fill_source_copy.base, fill_source, &m);
	fill_source = &fill_source_copy.base;
    }

    status = _cairo_surface_fill_stroke (wrapper->target,
					 fill_op, fill_source, fill_rule,
					 fill_tolerance, fill_antialias,
					 dev_path,
					 stroke_op, stroke_source,
					 stroke_style,
					 &dev_ctm, &dev_ctm_inverse,
					 stroke_tolerance, stroke_antialias,
					 dev_clip);

  FINISH:
    if (dev_path != path)
	_cairo_path_fixed_fini (dev_path);
    _cairo_clip_destroy (dev_clip);
    return status;
}
static cairo_int_status_t
_cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t		*pdf_operators,
				  const cairo_path_fixed_t	*path,
				  const cairo_stroke_style_t	*style,
				  const cairo_matrix_t		*ctm,
				  const cairo_matrix_t		*ctm_inverse,
				  const char			*pdf_operator)
{
    cairo_int_status_t status;
    cairo_matrix_t m, path_transform;
    cairo_bool_t has_ctm = TRUE;
    double scale = 1.0;

    if (pdf_operators->in_text_object) {
	status = _cairo_pdf_operators_end_text (pdf_operators);
	if (unlikely (status))
	    return status;
    }

    /* Optimize away the stroke ctm when it does not affect the
     * stroke. There are other ctm cases that could be optimized
     * however this is the most common.
     */
    if (fabs(ctm->xx) == 1.0 && fabs(ctm->yy) == 1.0 &&
	fabs(ctm->xy) == 0.0 && fabs(ctm->yx) == 0.0)
    {
	has_ctm = FALSE;
    }

    /* The PDF CTM is transformed to the user space CTM when stroking
     * so the corect pen shape will be used. This also requires that
     * the path be transformed to user space when emitted. The
     * conversion of path coordinates to user space may cause rounding
     * errors. For example the device space point (1.234, 3.142) when
     * transformed to a user space CTM of [100 0 0 100 0 0] will be
     * emitted as (0.012, 0.031).
     *
     * To avoid the rounding problem we scale the user space CTM
     * matrix so that all the non translation components of the matrix
     * are <= 1. The line width and and dashes are scaled by the
     * inverse of the scale applied to the CTM. This maintains the
     * shape of the stroke pen while keeping the user space CTM within
     * the range that maximizes the precision of the emitted path.
     */
    if (has_ctm) {
	m = *ctm;
	/* Zero out the translation since it does not affect the pen
	 * shape however it may cause unnecessary digits to be emitted.
	 */
	m.x0 = 0.0;
	m.y0 = 0.0;
	_cairo_matrix_factor_out_scale (&m, &scale);
	path_transform = m;
	status = cairo_matrix_invert (&path_transform);
	if (unlikely (status))
	    return status;

	cairo_matrix_multiply (&m, &m, &pdf_operators->cairo_to_pdf);
    }

    status = _cairo_pdf_operators_emit_stroke_style (pdf_operators, style, scale);
    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
	return CAIRO_STATUS_SUCCESS;
    if (unlikely (status))
	return status;

    if (has_ctm) {
	_cairo_output_stream_printf (pdf_operators->stream,
				     "q %f %f %f %f %f %f cm\n",
				     m.xx, m.yx, m.xy, m.yy,
				     m.x0, m.y0);
    } else {
	path_transform = pdf_operators->cairo_to_pdf;
    }

    status = _cairo_pdf_operators_emit_path (pdf_operators,
					     path,
					     &path_transform,
					     style->line_cap);
    if (unlikely (status))
	return status;

    _cairo_output_stream_printf (pdf_operators->stream, "%s", pdf_operator);
    if (has_ctm)
	_cairo_output_stream_printf (pdf_operators->stream, " Q");

    _cairo_output_stream_printf (pdf_operators->stream, "\n");

    return _cairo_output_stream_get_status (pdf_operators->stream);
}
Example #29
0
/**
 * _st_create_shadow_cairo_pattern:
 * @shadow_spec: the definition of the shadow
 * @src_pattern: surface pattern for which we create the shadow
 *               (must be a surface pattern)
 *
 * This is a utility function for creating shadows used by
 * st-theme-node.c; it's in this file to share the gaussian
 * blur implementation. The usage of this function is quite different
 * depending on whether shadow_spec->inset is %TRUE or not. If
 * shadow_spec->inset is %TRUE, the caller should pass in a @src_pattern
 * which is the <i>inverse</i> of what they want shadowed, and must take
 * care of the spread and offset from the shadow spec themselves. If
 * shadow_spec->inset is %FALSE then the caller should pass in what they
 * want shadowed directly, and this function takes care of the spread and
 * the offset.
 */
cairo_pattern_t *
_st_create_shadow_cairo_pattern (StShadow        *shadow_spec,
                                 cairo_pattern_t *src_pattern)
{
    static cairo_user_data_key_t shadow_pattern_user_data;
    cairo_t *cr;
    cairo_surface_t *src_surface;
    cairo_surface_t *surface_in;
    cairo_surface_t *surface_out;
    cairo_pattern_t *dst_pattern;
    guchar          *pixels_in, *pixels_out;
    gint             width_in, height_in, rowstride_in;
    gint             width_out, height_out, rowstride_out;
    cairo_matrix_t   shadow_matrix;
    int i, j;

    g_return_val_if_fail (shadow_spec != NULL, NULL);
    g_return_val_if_fail (src_pattern != NULL, NULL);

    cairo_pattern_get_surface (src_pattern, &src_surface);

    width_in  = cairo_image_surface_get_width  (src_surface);
    height_in = cairo_image_surface_get_height (src_surface);

    /* We want the output to be a color agnostic alpha mask,
     * so we need to strip the color channels from the input
     */
    if (cairo_image_surface_get_format (src_surface) != CAIRO_FORMAT_A8)
    {
        surface_in = cairo_image_surface_create (CAIRO_FORMAT_A8,
                     width_in, height_in);

        cr = cairo_create (surface_in);
        cairo_set_source_surface (cr, src_surface, 0, 0);
        cairo_paint (cr);
        cairo_destroy (cr);
    }
    else
    {
        surface_in = cairo_surface_reference (src_surface);
    }

    pixels_in = cairo_image_surface_get_data (surface_in);
    rowstride_in = cairo_image_surface_get_stride (surface_in);

    pixels_out = blur_pixels (pixels_in, width_in, height_in, rowstride_in,
                              shadow_spec->blur,
                              &width_out, &height_out, &rowstride_out);
    cairo_surface_destroy (surface_in);

    /* Invert pixels for inset shadows */
    if (shadow_spec->inset)
    {
        for (j = 0; j < height_out; j++)
        {
            guchar *p = pixels_out + rowstride_out * j;
            for (i = 0; i < width_out; i++, p++)
                *p = ~*p;
        }
    }

    surface_out = cairo_image_surface_create_for_data (pixels_out,
                  CAIRO_FORMAT_A8,
                  width_out,
                  height_out,
                  rowstride_out);
    cairo_surface_set_user_data (surface_out, &shadow_pattern_user_data,
                                 pixels_out, (cairo_destroy_func_t) g_free);

    dst_pattern = cairo_pattern_create_for_surface (surface_out);
    cairo_surface_destroy (surface_out);

    cairo_pattern_get_matrix (src_pattern, &shadow_matrix);

    if (shadow_spec->inset)
    {
        /* For inset shadows, offsets and spread radius have already been
         * applied to the original pattern, so all left to do is shift the
         * blurred image left, so that it aligns centered under the
         * unblurred one
         */
        cairo_matrix_translate (&shadow_matrix,
                                (width_out - width_in) / 2.0,
                                (height_out - height_in) / 2.0);
        cairo_pattern_set_matrix (dst_pattern, &shadow_matrix);
        return dst_pattern;
    }

    /* Read all the code from the cairo_pattern_set_matrix call
     * at the end of this function to here from bottom to top,
     * because each new affine transformation is applied in
     * front of all the previous ones */

    /* 6. Invert the matrix back */
    cairo_matrix_invert (&shadow_matrix);

    /* 5. Adjust based on specified offsets */
    cairo_matrix_translate (&shadow_matrix,
                            shadow_spec->xoffset,
                            shadow_spec->yoffset);

    /* 4. Recenter the newly scaled image */
    cairo_matrix_translate (&shadow_matrix,
                            - shadow_spec->spread,
                            - shadow_spec->spread);

    /* 3. Scale up the blurred image to fill the spread */
    cairo_matrix_scale (&shadow_matrix,
                        (width_in + 2.0 * shadow_spec->spread) / width_in,
                        (height_in + 2.0 * shadow_spec->spread) / height_in);

    /* 2. Shift the blurred image left, so that it aligns centered
     * under the unblurred one */
    cairo_matrix_translate (&shadow_matrix,
                            - (width_out - width_in) / 2.0,
                            - (height_out - height_in) / 2.0);

    /* 1. Invert the matrix so we can work with it in pattern space
     */
    cairo_matrix_invert (&shadow_matrix);

    cairo_pattern_set_matrix (dst_pattern, &shadow_matrix);

    return dst_pattern;
}
Example #30
0
static PyObject *
matrix_invert (PycairoMatrix *o) {
  if (Pycairo_Check_Status (cairo_matrix_invert (&o->matrix)))
    return NULL;
  Py_RETURN_NONE;
}