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); }
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"); } }
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); } }
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; } }
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; }
/* 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; }
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); }
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; }
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(); } }
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); } }
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; }
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); }
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; }
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); } }
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; }
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); }
int32_t Matrix::invert() { return static_cast<int32_t>( cairo_matrix_invert( &getCairoMatrix() ) ); }
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; }
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); }
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]; } }
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); }
/** * _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; }
static PyObject * matrix_invert (PycairoMatrix *o) { if (Pycairo_Check_Status (cairo_matrix_invert (&o->matrix))) return NULL; Py_RETURN_NONE; }