Esempio n. 1
0
cairo_t *
gsk_cairo_blur_finish_drawing (cairo_t         *cr,
                               float            radius,
                               const GdkRGBA   *color,
                               GskBlurFlags     blur_flags)
{
  cairo_t *original_cr;
  cairo_surface_t *surface;
  gdouble x_scale;

  if (!needs_blur (radius))
    return cr;

  original_cr = cairo_get_user_data (cr, &original_cr_key);

  /* Blur the surface. */
  surface = cairo_get_target (cr);

  x_scale = 1;
  cairo_surface_get_device_scale (cairo_get_target (cr), &x_scale, NULL);

  gsk_cairo_blur_surface (surface, x_scale * radius, blur_flags);

  gdk_cairo_set_source_rgba (original_cr, color);
  if (blur_flags & GSK_BLUR_REPEAT)
    mask_surface_repeat (original_cr, surface);
  else
    cairo_mask_surface (original_cr, surface, 0, 0);

  cairo_destroy (cr);

  cairo_surface_destroy (surface);

  return original_cr;
}
Esempio n. 2
0
static void
get_surface_size (GtkIconHelper   *self,
		  GtkStyleContext *context,
		  cairo_surface_t *surface,
		  int *width,
		  int *height)
{
  double x_scale, y_scale;

  if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE)
    {
      x_scale = y_scale = 1;

#ifdef HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE
      cairo_surface_get_device_scale (surface, &x_scale, &y_scale);
#endif

      /* Assume any set scaling is icon scale */
      *width =
	ceil (cairo_image_surface_get_width (surface) / x_scale);
      *height =
	ceil (cairo_image_surface_get_height (surface) / y_scale);
    }
  else
    ensure_icon_size (self, context, width, height);
}
Esempio n. 3
0
cairo_t *
gsk_cairo_blur_start_drawing (cairo_t         *cr,
                              float            radius,
                              GskBlurFlags     blur_flags)
{
  cairo_rectangle_int_t clip_rect;
  cairo_surface_t *surface;
  cairo_t *blur_cr;
  gdouble clip_radius;
  gdouble x_scale, y_scale;
  gboolean blur_x = (blur_flags & GSK_BLUR_X) != 0;
  gboolean blur_y = (blur_flags & GSK_BLUR_Y) != 0;

  if (!needs_blur (radius))
    return cr;

  gdk_cairo_get_clip_rectangle (cr, &clip_rect);

  clip_radius = gsk_cairo_blur_compute_pixels (radius);

  x_scale = y_scale = 1;
  cairo_surface_get_device_scale (cairo_get_target (cr), &x_scale, &y_scale);

  if (blur_flags & GSK_BLUR_REPEAT)
    {
      if (!blur_x)
        clip_rect.width = 1;
      if (!blur_y)
        clip_rect.height = 1;
    }

  /* Create a larger surface to center the blur. */
  surface = cairo_surface_create_similar_image (cairo_get_target (cr),
                                                CAIRO_FORMAT_A8,
                                                x_scale * (clip_rect.width + (blur_x ? 2 * clip_radius : 0)),
                                                y_scale * (clip_rect.height + (blur_y ? 2 * clip_radius : 0)));
  cairo_surface_set_device_scale (surface, x_scale, y_scale);
  cairo_surface_set_device_offset (surface,
                                    x_scale * ((blur_x ? clip_radius : 0) - clip_rect.x),
                                    y_scale * ((blur_y ? clip_radius : 0) - clip_rect.y));

  blur_cr = cairo_create (surface);
  cairo_set_user_data (blur_cr, &original_cr_key, cairo_reference (cr), (cairo_destroy_func_t) cairo_destroy);

  if (cairo_has_current_point (cr))
    {
      double x, y;

      cairo_get_current_point (cr, &x, &y);
      cairo_move_to (blur_cr, x, y);
    }

  return blur_cr;
}
Esempio n. 4
0
static void
gtk_css_image_surface_draw (GtkCssImage *image,
                            cairo_t     *cr,
                            double       width,
                            double       height)
{
  GtkCssImageSurface *surface = GTK_CSS_IMAGE_SURFACE (image);
  int image_width, image_height;

  image_width = cairo_image_surface_get_width (surface->surface);
  image_height = cairo_image_surface_get_height (surface->surface);

  if (image_width == 0 || image_height == 0 || width <= 0 || height <= 0)
    return;

  /* Update cache image if size is different */
  if (surface->cache == NULL   ||
      ABS (width - surface->width) > 0.001 ||
      ABS (height - surface->height) > 0.001)
    {
      double xscale, yscale;
      cairo_t *cache;

      /* We need the device scale (HiDPI mode) to calculate the proper size in
       * pixels for the image surface and set the cache device scale
       */
      cairo_surface_get_device_scale (cairo_get_target (cr), &xscale, &yscale);

      /* Save original size to preserve precision */
      surface->width = width;
      surface->height = height;

      /* Destroy old cache if any */
      g_clear_pointer (&surface->cache, cairo_surface_destroy);

      /* Image big enough to contain scaled image with subpixel precision */
      surface->cache = cairo_surface_create_similar_image (surface->surface,
                                                           CAIRO_FORMAT_ARGB32,
                                                           ceil (width*xscale),
                                                           ceil (height*yscale));
      cairo_surface_set_device_scale (surface->cache, xscale, yscale);
      cache = cairo_create (surface->cache);
      cairo_rectangle (cache, 0, 0, width, height);
      cairo_scale (cache, width / image_width, height / image_height);
      cairo_set_source_surface (cache, surface->surface, 0, 0);
      cairo_fill (cache);

      cairo_destroy (cache);
    }

  cairo_rectangle (cr, 0, 0, width, height);
  cairo_set_source_surface (cr, surface->cache ? surface->cache : surface->surface, 0, 0);
  cairo_fill (cr);
}
Esempio n. 5
0
/**
 * gdk_cursor_get_image:
 * @cursor: a #GdkCursor
 *
 * Returns a #GdkPixbuf with the image used to display the cursor.
 *
 * Note that depending on the capabilities of the windowing system and 
 * on the cursor, GDK may not be able to obtain the image data. In this 
 * case, %NULL is returned.
 *
 * Returns: (transfer full): a #GdkPixbuf representing @cursor, or %NULL
 *
 * Since: 2.8
 */
GdkPixbuf*  
gdk_cursor_get_image (GdkCursor *cursor)
{
  int w, h;
  cairo_surface_t *surface;
  GdkPixbuf *pixbuf;
  gchar buf[32];
  double x_hot, y_hot;
  double x_scale, y_scale;

  g_return_val_if_fail (GDK_IS_CURSOR (cursor), NULL);

  surface = gdk_cursor_get_surface (cursor, &x_hot, &y_hot);
  if (surface == NULL)
    return NULL;

  w = cairo_image_surface_get_width (surface);
  h = cairo_image_surface_get_height (surface);

  x_scale = y_scale = 1;
#ifdef HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE
  cairo_surface_get_device_scale (surface, &x_scale, &y_scale);
#endif

  pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, w, h);
  cairo_surface_destroy (surface);

  if (x_scale != 1)
    {
      GdkPixbuf *old;

      old = pixbuf;
      pixbuf = gdk_pixbuf_scale_simple (old,
					w / x_scale, h / y_scale,
					GDK_INTERP_HYPER);
      g_object_unref (old);
    }

  
  g_snprintf (buf, 32, "%d", (int)x_hot);
  gdk_pixbuf_set_option (pixbuf, "x_hot", buf);

  g_snprintf (buf, 32, "%d", (int)y_hot);
  gdk_pixbuf_set_option (pixbuf, "y_hot", buf);

  return pixbuf;
}
Esempio n. 6
0
cairo_surface_t *
_gtk_css_image_get_surface (GtkCssImage     *image,
                            cairo_surface_t *target,
                            int              surface_width,
                            int              surface_height)
{
  cairo_surface_t *result;
  cairo_t *cr;
  double sx, sy;

  g_return_val_if_fail (GTK_IS_CSS_IMAGE (image), NULL);
  g_return_val_if_fail (surface_width > 0, NULL);
  g_return_val_if_fail (surface_height > 0, NULL);


  if (target)
    {
#ifdef HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE
      cairo_surface_get_device_scale (target, &sx, &sy);
#else
      sx = sy = 1;
#endif

      result = cairo_surface_create_similar (target,
					     CAIRO_CONTENT_COLOR_ALPHA,
					     surface_width*sx,
					     surface_height*sy);

#ifdef HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE
      cairo_surface_set_device_scale (result, sx, sy);
#endif
    }
  else
    result = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
                                         surface_width,
                                         surface_height);

  cr = cairo_create (result);
  _gtk_css_image_draw (image, cr, surface_width, surface_height);
  cairo_destroy (cr);

  return result;
}
Esempio n. 7
0
static void
text_to_glyphs (cairo_t *cr,
                const gchar *text,
                cairo_glyph_t **glyphs,
                int *num_glyphs)
{
  PangoAttribute *fallback_attr;
  PangoAttrList *attr_list;
  PangoContext *context;
  PangoDirection base_dir;
  GList *items;
  GList *visual_items;
  FT_Face ft_face;
  hb_font_t *hb_font;
  gdouble x = 0, y = 0;
  gint i;
  gdouble x_scale, y_scale;

  *num_glyphs = 0;
  *glyphs = NULL;

  base_dir = pango_find_base_dir (text, -1);

  cairo_scaled_font_t *cr_font = cairo_get_scaled_font (cr);
  ft_face = cairo_ft_scaled_font_lock_face (cr_font);
  hb_font = hb_ft_font_create (ft_face, NULL);

  cairo_surface_t *target = cairo_get_target (cr);
  cairo_surface_get_device_scale (target, &x_scale, &y_scale);

  /* We abuse pango itemazation to split text into script and direction
   * runs, since we use our fonts directly no through pango, we don't
   * bother changing the default font, but we disable font fallback as
   * pango will split runs at font change */
  context = pango_cairo_create_context (cr);
  attr_list = pango_attr_list_new ();
  fallback_attr = pango_attr_fallback_new (FALSE);
  pango_attr_list_insert (attr_list, fallback_attr);
  items = pango_itemize_with_base_dir (context, base_dir,
                                       text, 0, strlen (text),
                                       attr_list, NULL);
  g_object_unref (context);
  pango_attr_list_unref (attr_list);

  /* reorder the items in the visual order */
  visual_items = pango_reorder_items (items);

  while (visual_items) {
    PangoItem *item;
    PangoAnalysis analysis;
    hb_buffer_t *hb_buffer;
    hb_glyph_info_t *hb_glyphs;
    hb_glyph_position_t *hb_positions;
    gint n;

    item = visual_items->data;
    analysis = item->analysis;

    hb_buffer = hb_buffer_create ();
    hb_buffer_add_utf8 (hb_buffer, text, -1, item->offset, item->length);
    hb_buffer_set_script (hb_buffer, hb_glib_script_to_script (analysis.script));
    hb_buffer_set_language (hb_buffer, hb_language_from_string (pango_language_to_string (analysis.language), -1));
    hb_buffer_set_direction (hb_buffer, analysis.level % 2 ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);

    hb_shape (hb_font, hb_buffer, NULL, 0);

    n = hb_buffer_get_length (hb_buffer);
    hb_glyphs = hb_buffer_get_glyph_infos (hb_buffer, NULL);
    hb_positions = hb_buffer_get_glyph_positions (hb_buffer, NULL);

    *glyphs = g_renew (cairo_glyph_t, *glyphs, *num_glyphs + n);

    for (i = 0; i < n; i++) {
      (*glyphs)[*num_glyphs + i].index = hb_glyphs[i].codepoint;
      (*glyphs)[*num_glyphs + i].x = x + (hb_positions[i].x_offset / (64. * x_scale));
      (*glyphs)[*num_glyphs + i].y = y - (hb_positions[i].y_offset / (64. * y_scale));
      x += (hb_positions[i].x_advance / (64. * x_scale));
      y -= (hb_positions[i].y_advance / (64. * y_scale));
    }

    *num_glyphs += n;

    hb_buffer_destroy (hb_buffer);

    visual_items = visual_items->next;
  }

  g_list_free_full (visual_items, (GDestroyNotify) pango_item_free);
  g_list_free_full (items, (GDestroyNotify) pango_item_free);

  hb_font_destroy (hb_font);
  cairo_ft_scaled_font_unlock_face (cr_font);
}
Esempio n. 8
0
/* This is always called with the paint context current */
void
gdk_gl_texture_from_surface (cairo_surface_t *surface,
                             cairo_region_t  *region)
{
    GdkGLContext *paint_context;
    cairo_surface_t *image;
    double device_x_offset, device_y_offset;
    cairo_rectangle_int_t rect, e;
    int n_rects, i;
    GdkWindow *window;
    int unscaled_window_height;
    unsigned int texture_id;
    int window_scale;
    double sx, sy;
    float umax, vmax;
    gboolean use_texture_rectangle;
    guint target;
    paint_context = gdk_gl_context_get_current ();
    if ((_gdk_gl_flags & GDK_GL_SOFTWARE_DRAW_SURFACE) == 0 &&
            paint_context &&
            GDK_GL_CONTEXT_GET_CLASS (paint_context)->texture_from_surface &&
            GDK_GL_CONTEXT_GET_CLASS (paint_context)->texture_from_surface (paint_context, surface, region))
        return;

    /* Software fallback */
    use_texture_rectangle = gdk_gl_context_use_texture_rectangle (paint_context);

    window = gdk_gl_context_get_window (paint_context);
    window_scale = gdk_window_get_scale_factor (window);
    gdk_window_get_unscaled_size (window, NULL, &unscaled_window_height);

    sx = sy = 1;
    cairo_surface_get_device_scale (window->current_paint.surface, &sx, &sy);

    cairo_surface_get_device_offset (surface,
                                     &device_x_offset, &device_y_offset);

    glGenTextures (1, &texture_id);
    if (use_texture_rectangle)
        target = GL_TEXTURE_RECTANGLE_ARB;
    else
        target = GL_TEXTURE_2D;

    glBindTexture (target, texture_id);
    glEnable (GL_SCISSOR_TEST);

    glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    n_rects = cairo_region_num_rectangles (region);

#define FLIP_Y(_y) (unscaled_window_height - (_y))

    for (i = 0; i < n_rects; i++)
    {
        cairo_region_get_rectangle (region, i, &rect);

        glScissor (rect.x * window_scale, FLIP_Y ((rect.y + rect.height) * window_scale),
                   rect.width * window_scale, rect.height * window_scale);

        e = rect;
        e.x *= sx;
        e.y *= sy;
        e.x += (int)device_x_offset;
        e.y += (int)device_y_offset;
        e.width *= sx;
        e.height *= sy;
        image = cairo_surface_map_to_image (surface, &e);

        gdk_gl_context_upload_texture (paint_context, image, e.width, e.height, target);

        cairo_surface_unmap_image (surface, image);

        if (use_texture_rectangle)
        {
            umax = rect.width * sx;
            vmax = rect.height * sy;
        }
        else
        {
            umax = 1.0;
            vmax = 1.0;
        }

        {
            GdkTexturedQuad quad = {
                rect.x * window_scale, FLIP_Y(rect.y * window_scale),
                (rect.x + rect.width) * window_scale, FLIP_Y((rect.y + rect.height) * window_scale),
                0, 0,
                umax, vmax,
            };

            /* We don't want to combine the quads here, because they have different textures.
             * And we don't want to upload the unused source areas to make it one texture. */
            gdk_gl_texture_quads (paint_context, target, 1, &quad);
        }
    }

#undef FLIP_Y

    glDisable (GL_SCISSOR_TEST);
    glDeleteTextures (1, &texture_id);
}
Esempio n. 9
0
/**
 * gd_embed_surface_in_frame:
 * @source_image:
 * @frame_image_url:
 * @slice_width:
 * @border_width:
 *
 * Returns: (transfer full):
 */
cairo_surface_t *
gd_embed_surface_in_frame (cairo_surface_t *source_image,
                           const gchar *frame_image_url,
                           GtkBorder *slice_width,
                           GtkBorder *border_width)
{
  cairo_surface_t *surface;
  cairo_t *cr;
  int source_width, source_height;
  gchar *css_str;
  GtkCssProvider *provider;
  GtkStyleContext *context;
  GError *error = NULL;
  GdkPixbuf *retval;
  GtkWidgetPath *path;
  gdouble scale_x, scale_y;

  cairo_surface_get_device_scale (source_image, &scale_x, &scale_y);

  source_width = cairo_image_surface_get_width (source_image) / (gint) floor (scale_x),
  source_height = cairo_image_surface_get_height (source_image) / (gint) floor (scale_y);

  css_str = g_strdup_printf (".embedded-image { border-image: url(\"%s\") %d %d %d %d / %dpx %dpx %dpx %dpx }",
                             frame_image_url,
                             slice_width->top, slice_width->right, slice_width->bottom, slice_width->left,
                             border_width->top, border_width->right, border_width->bottom, border_width->left);
  provider = gtk_css_provider_new ();
  gtk_css_provider_load_from_data (provider, css_str, -1, &error);

  if (error != NULL)
    {
      g_warning ("Unable to create the thumbnail frame image: %s", error->message);
      g_error_free (error);
      g_free (css_str);

      return g_object_ref (source_image);
    }

  surface = cairo_surface_create_similar (source_image,
                                          CAIRO_CONTENT_COLOR_ALPHA,
                                          source_width, source_height);
  cr = cairo_create (surface);

  context = gtk_style_context_new ();
  path = gtk_widget_path_new ();
  gtk_widget_path_append_type (path, GTK_TYPE_ICON_VIEW);

  gtk_style_context_set_path (context, path);
  gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), 600);

  cairo_save (cr);
  cairo_rectangle (cr,
		   border_width->left,
		   border_width->top,
		   source_width - border_width->left - border_width->right,
		   source_height - border_width->top - border_width->bottom);
  cairo_clip (cr);
  gtk_render_icon_surface (context, cr,
                           source_image,
                           0, 0);
  cairo_restore (cr);

  gtk_style_context_save (context);
  gtk_style_context_add_class (context, "embedded-image");

  gtk_render_frame (context, cr,
                    0, 0,
                    source_width, source_height);

  gtk_style_context_restore (context);
  cairo_destroy (cr);

  gtk_widget_path_unref (path);
  g_object_unref (provider);
  g_object_unref (context);
  g_free (css_str);

  return surface;
}