Blame tests/testcairo.c

Packit 98cdb6
/* testimage.c
Packit 98cdb6
 * Copyright (C) 2005  Red Hat, Inc.
Packit 98cdb6
 * Based on cairo-demo/X11/cairo-knockout.c
Packit 98cdb6
 *
Packit 98cdb6
 * Author: Owen Taylor
Packit 98cdb6
 *
Packit 98cdb6
 * This library is free software; you can redistribute it and/or
Packit 98cdb6
 * modify it under the terms of the GNU Library General Public
Packit 98cdb6
 * License as published by the Free Software Foundation; either
Packit 98cdb6
 * version 2 of the License, or (at your option) any later version.
Packit 98cdb6
 *
Packit 98cdb6
 * This library is distributed in the hope that it will be useful,
Packit 98cdb6
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 98cdb6
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 98cdb6
 * Library General Public License for more details.
Packit 98cdb6
 *
Packit 98cdb6
 * You should have received a copy of the GNU Library General Public
Packit 98cdb6
 * License along with this library; if not, write to the
Packit 98cdb6
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Packit 98cdb6
 * Boston, MA 02111-1307, USA.
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
#include <math.h>
Packit 98cdb6
Packit 98cdb6
#include <gtk/gtk.h>
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
oval_path (cairo_t *cr,
Packit 98cdb6
           double xc, double yc,
Packit 98cdb6
           double xr, double yr)
Packit 98cdb6
{
Packit 98cdb6
  cairo_save (cr);
Packit 98cdb6
Packit 98cdb6
  cairo_translate (cr, xc, yc);
Packit 98cdb6
  cairo_scale (cr, 1.0, yr / xr);
Packit 98cdb6
  cairo_move_to (cr, xr, 0.0);
Packit 98cdb6
  cairo_arc (cr,
Packit 98cdb6
	     0, 0,
Packit 98cdb6
	     xr,
Packit 98cdb6
	     0, 2 * G_PI);
Packit 98cdb6
  cairo_close_path (cr);
Packit 98cdb6
Packit 98cdb6
  cairo_restore (cr);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/* Create a path that is a circular oval with radii xr, yr at xc,
Packit 98cdb6
 * yc.
Packit 98cdb6
 */
Packit 98cdb6
/* Fill the given area with checks in the standard style
Packit 98cdb6
 * for showing compositing effects.
Packit 98cdb6
 *
Packit 98cdb6
 * It would make sense to do this as a repeating surface,
Packit 98cdb6
 * but most implementations of RENDER currently have broken
Packit 98cdb6
 * implementations of repeat + transform, even when the
Packit 98cdb6
 * transform is a translation.
Packit 98cdb6
 */
Packit 98cdb6
static void
Packit 98cdb6
fill_checks (cairo_t *cr,
Packit 98cdb6
             int x,     int y,
Packit 98cdb6
             int width, int height)
Packit 98cdb6
{
Packit 98cdb6
  int i, j;
Packit 98cdb6
  
Packit 98cdb6
#define CHECK_SIZE 32
Packit 98cdb6
Packit 98cdb6
  cairo_rectangle (cr, x, y, width, height);
Packit 98cdb6
  cairo_set_source_rgb (cr, 0.4, 0.4, 0.4);
Packit 98cdb6
  cairo_fill (cr);
Packit 98cdb6
Packit 98cdb6
  /* Only works for CHECK_SIZE a power of 2 */
Packit 98cdb6
  j = x & (-CHECK_SIZE);
Packit 98cdb6
  
Packit 98cdb6
  for (; j < height; j += CHECK_SIZE)
Packit 98cdb6
    {
Packit 98cdb6
      i = y & (-CHECK_SIZE);
Packit 98cdb6
      for (; i < width; i += CHECK_SIZE)
Packit 98cdb6
	if ((i / CHECK_SIZE + j / CHECK_SIZE) % 2 == 0)
Packit 98cdb6
	  cairo_rectangle (cr, i, j, CHECK_SIZE, CHECK_SIZE);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  cairo_set_source_rgb (cr, 0.7, 0.7, 0.7);
Packit 98cdb6
  cairo_fill (cr);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/* Draw a red, green, and blue circle equally spaced inside
Packit 98cdb6
 * the larger circle of radius r at (xc, yc)
Packit 98cdb6
 */
Packit 98cdb6
static void
Packit 98cdb6
draw_3circles (cairo_t *cr,
Packit 98cdb6
               double xc, double yc,
Packit 98cdb6
               double radius,
Packit 98cdb6
	       double alpha)
Packit 98cdb6
{
Packit 98cdb6
  double subradius = radius * (2 / 3. - 0.1);
Packit 98cdb6
    
Packit 98cdb6
  cairo_set_source_rgba (cr, 1., 0., 0., alpha);
Packit 98cdb6
  oval_path (cr,
Packit 98cdb6
	     xc + radius / 3. * cos (G_PI * (0.5)),
Packit 98cdb6
	     yc - radius / 3. * sin (G_PI * (0.5)),
Packit 98cdb6
	     subradius, subradius);
Packit 98cdb6
  cairo_fill (cr);
Packit 98cdb6
    
Packit 98cdb6
  cairo_set_source_rgba (cr, 0., 1., 0., alpha);
Packit 98cdb6
  oval_path (cr,
Packit 98cdb6
	     xc + radius / 3. * cos (G_PI * (0.5 + 2/.3)),
Packit 98cdb6
	     yc - radius / 3. * sin (G_PI * (0.5 + 2/.3)),
Packit 98cdb6
	     subradius, subradius);
Packit 98cdb6
  cairo_fill (cr);
Packit 98cdb6
    
Packit 98cdb6
  cairo_set_source_rgba (cr, 0., 0., 1., alpha);
Packit 98cdb6
  oval_path (cr,
Packit 98cdb6
	     xc + radius / 3. * cos (G_PI * (0.5 + 4/.3)),
Packit 98cdb6
	     yc - radius / 3. * sin (G_PI * (0.5 + 4/.3)),
Packit 98cdb6
	     subradius, subradius);
Packit 98cdb6
  cairo_fill (cr);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
draw (cairo_t *cr,
Packit 98cdb6
      int      width,
Packit 98cdb6
      int      height)
Packit 98cdb6
{
Packit 98cdb6
  cairo_surface_t *overlay, *punch, *circles;
Packit 98cdb6
  cairo_t *overlay_cr, *punch_cr, *circles_cr;
Packit 98cdb6
Packit 98cdb6
  /* Fill the background */
Packit 98cdb6
  double radius = 0.5 * (width < height ? width : height) - 10;
Packit 98cdb6
  double xc = width / 2.;
Packit 98cdb6
  double yc = height / 2.;
Packit 98cdb6
Packit 98cdb6
  overlay = cairo_surface_create_similar (cairo_get_target (cr),
Packit 98cdb6
					  CAIRO_CONTENT_COLOR_ALPHA,
Packit 98cdb6
					  width, height);
Packit 98cdb6
  if (overlay == NULL)
Packit 98cdb6
    return;
Packit 98cdb6
Packit 98cdb6
  punch = cairo_surface_create_similar (cairo_get_target (cr),
Packit 98cdb6
					CAIRO_CONTENT_ALPHA,
Packit 98cdb6
					width, height);
Packit 98cdb6
  if (punch == NULL)
Packit 98cdb6
    return;
Packit 98cdb6
Packit 98cdb6
  circles = cairo_surface_create_similar (cairo_get_target (cr),
Packit 98cdb6
					  CAIRO_CONTENT_COLOR_ALPHA,
Packit 98cdb6
					  width, height);
Packit 98cdb6
  if (circles == NULL)
Packit 98cdb6
    return;
Packit 98cdb6
    
Packit 98cdb6
  fill_checks (cr, 0, 0, width, height);
Packit 98cdb6
Packit 98cdb6
  /* Draw a black circle on the overlay
Packit 98cdb6
   */
Packit 98cdb6
  overlay_cr = cairo_create (overlay);
Packit 98cdb6
  cairo_set_source_rgb (overlay_cr, 0., 0., 0.);
Packit 98cdb6
  oval_path (overlay_cr, xc, yc, radius, radius);
Packit 98cdb6
  cairo_fill (overlay_cr);
Packit 98cdb6
Packit 98cdb6
  /* Draw 3 circles to the punch surface, then cut
Packit 98cdb6
   * that out of the main circle in the overlay
Packit 98cdb6
   */
Packit 98cdb6
  punch_cr = cairo_create (punch);
Packit 98cdb6
  draw_3circles (punch_cr, xc, yc, radius, 1.0);
Packit 98cdb6
  cairo_destroy (punch_cr);
Packit 98cdb6
Packit 98cdb6
  cairo_set_operator (overlay_cr, CAIRO_OPERATOR_DEST_OUT);
Packit 98cdb6
  cairo_set_source_surface (overlay_cr, punch, 0, 0);
Packit 98cdb6
  cairo_paint (overlay_cr);
Packit 98cdb6
Packit 98cdb6
  /* Now draw the 3 circles in a subgroup again
Packit 98cdb6
   * at half intensity, and use OperatorAdd to join up
Packit 98cdb6
   * without seams.
Packit 98cdb6
   */
Packit 98cdb6
  circles_cr = cairo_create (circles);
Packit 98cdb6
  
Packit 98cdb6
  cairo_set_operator (circles_cr, CAIRO_OPERATOR_OVER);
Packit 98cdb6
  draw_3circles (circles_cr, xc, yc, radius, 0.5);
Packit 98cdb6
  cairo_destroy (circles_cr);
Packit 98cdb6
Packit 98cdb6
  cairo_set_operator (overlay_cr, CAIRO_OPERATOR_ADD);
Packit 98cdb6
  cairo_set_source_surface (overlay_cr, circles, 0, 0);
Packit 98cdb6
  cairo_paint (overlay_cr);
Packit 98cdb6
Packit 98cdb6
  cairo_destroy (overlay_cr);
Packit 98cdb6
Packit 98cdb6
  cairo_set_source_surface (cr, overlay, 0, 0);
Packit 98cdb6
  cairo_paint (cr);
Packit 98cdb6
Packit 98cdb6
  cairo_surface_destroy (overlay);
Packit 98cdb6
  cairo_surface_destroy (punch);
Packit 98cdb6
  cairo_surface_destroy (circles);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static gboolean
Packit 98cdb6
on_expose_event (GtkWidget      *widget,
Packit 98cdb6
		 GdkEventExpose *event,
Packit 98cdb6
		 gpointer        data)
Packit 98cdb6
{
Packit 98cdb6
  cairo_t *cr;
Packit 98cdb6
Packit 98cdb6
  cr = gdk_cairo_create (widget->window);
Packit 98cdb6
Packit 98cdb6
  draw (cr, widget->allocation.width, widget->allocation.height);
Packit 98cdb6
Packit 98cdb6
  cairo_destroy (cr);
Packit 98cdb6
Packit 98cdb6
  return FALSE;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
int
Packit 98cdb6
main (int argc, char **argv)
Packit 98cdb6
{
Packit 98cdb6
  GtkWidget *window, *darea;
Packit 98cdb6
Packit 98cdb6
  gtk_init (&argc, &argv);
Packit 98cdb6
Packit 98cdb6
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
Packit 98cdb6
  
Packit 98cdb6
  gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
Packit 98cdb6
  gtk_window_set_title (GTK_WINDOW (window), "cairo: Knockout Groups");
Packit 98cdb6
Packit 98cdb6
  darea = gtk_drawing_area_new ();
Packit 98cdb6
  gtk_container_add (GTK_CONTAINER (window), darea);
Packit 98cdb6
Packit 98cdb6
  g_signal_connect (darea, "expose-event",
Packit 98cdb6
		    G_CALLBACK (on_expose_event), NULL);
Packit 98cdb6
  g_signal_connect (window, "destroy-event",
Packit 98cdb6
		    G_CALLBACK (gtk_main_quit), NULL);
Packit 98cdb6
Packit 98cdb6
  gtk_widget_show_all (window);
Packit 98cdb6
  
Packit 98cdb6
  gtk_main ();
Packit 98cdb6
Packit 98cdb6
  return 0;
Packit 98cdb6
}