Beispiel #1
0
static cairo_status_t
_cairo_meta_surface_replay_internal (cairo_surface_t	     *surface,
				     cairo_surface_t	     *target,
				     cairo_meta_replay_type_t type,
				     cairo_meta_region_type_t region)
{
    cairo_meta_surface_t *meta;
    cairo_command_t *command, **elements;
    int i, num_elements;
    cairo_int_status_t status, status2;
    cairo_clip_t clip, *old_clip;
    cairo_bool_t has_device_transform = _cairo_surface_has_device_transform (target);
    cairo_matrix_t *device_transform = &target->device_transform;
    cairo_path_fixed_t path_copy, *dev_path;

    if (surface->status)
	return surface->status;

    if (target->status)
	return _cairo_surface_set_error (surface, target->status);

    meta = (cairo_meta_surface_t *) surface;
    status = CAIRO_STATUS_SUCCESS;

    _cairo_clip_init (&clip, target);
    old_clip = _cairo_surface_get_clip (target);

    num_elements = meta->commands.num_elements;
    elements = _cairo_array_index (&meta->commands, 0);
    for (i = meta->replay_start_idx; i < num_elements; i++) {
	command = elements[i];

	if (type == CAIRO_META_REPLAY && region != CAIRO_META_REGION_ALL) {
	    if (command->header.region != region)
		continue;
        }

	/* For all commands except intersect_clip_path, we have to
	 * ensure the current clip gets set on the surface. */
	if (command->header.type != CAIRO_COMMAND_INTERSECT_CLIP_PATH) {
	    status = _cairo_surface_set_clip (target, &clip);
	    if (status)
		break;
	}

	dev_path = _cairo_command_get_path (command);
	if (dev_path && has_device_transform) {
	    status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
	    if (status)
		break;
	    _cairo_path_fixed_transform (&path_copy, device_transform);
	    dev_path = &path_copy;
	}

	switch (command->header.type) {
	case CAIRO_COMMAND_PAINT:
	    status = _cairo_surface_paint (target,
					   command->paint.op,
					   &command->paint.source.base);
	    break;
	case CAIRO_COMMAND_MASK:
	    status = _cairo_surface_mask (target,
					  command->mask.op,
					  &command->mask.source.base,
					  &command->mask.mask.base);
	    break;
	case CAIRO_COMMAND_STROKE:
	{
	    cairo_matrix_t dev_ctm = command->stroke.ctm;
	    cairo_matrix_t dev_ctm_inverse = command->stroke.ctm_inverse;

	    if (has_device_transform) {
		cairo_matrix_multiply (&dev_ctm, &dev_ctm, device_transform);
		cairo_matrix_multiply (&dev_ctm_inverse,
				       &surface->device_transform_inverse,
				       &dev_ctm_inverse);
	    }

	    status = _cairo_surface_stroke (target,
					    command->stroke.op,
					    &command->stroke.source.base,
					    dev_path,
					    &command->stroke.style,
					    &dev_ctm,
					    &dev_ctm_inverse,
					    command->stroke.tolerance,
					    command->stroke.antialias);
	    break;
	}
	case CAIRO_COMMAND_FILL:
	{
	    cairo_command_t *stroke_command;

	    if (type != CAIRO_META_CREATE_REGIONS)
		stroke_command = (i < num_elements - 1) ? elements[i + 1] : NULL;
	    else
		stroke_command = NULL;

	    if (stroke_command != NULL &&
		type == CAIRO_META_REPLAY && region != CAIRO_META_REGION_ALL)
	    {
		if (stroke_command->header.region != region)
		    stroke_command = NULL;
	    }
	    if (stroke_command != NULL &&
		stroke_command->header.type == CAIRO_COMMAND_STROKE &&
		_cairo_path_fixed_is_equal (dev_path, _cairo_command_get_path (stroke_command))) {
		cairo_matrix_t dev_ctm;
		cairo_matrix_t dev_ctm_inverse;

		dev_ctm = stroke_command->stroke.ctm;
		dev_ctm_inverse = stroke_command->stroke.ctm_inverse;

		if (has_device_transform) {
		    cairo_matrix_multiply (&dev_ctm, &dev_ctm, device_transform);
		    cairo_matrix_multiply (&dev_ctm_inverse,
					   &surface->device_transform_inverse,
					   &dev_ctm_inverse);
		}

		status = _cairo_surface_fill_stroke (target,
						     command->fill.op,
						     &command->fill.source.base,
						     command->fill.fill_rule,
						     command->fill.tolerance,
						     command->fill.antialias,
						     dev_path,
						     stroke_command->stroke.op,
						     &stroke_command->stroke.source.base,
						     &stroke_command->stroke.style,
						     &dev_ctm,
						     &dev_ctm_inverse,
						     stroke_command->stroke.tolerance,
						     stroke_command->stroke.antialias);
		i++;
	    } else
		status = _cairo_surface_fill (target,
					      command->fill.op,
					      &command->fill.source.base,
					      dev_path,
					      command->fill.fill_rule,
					      command->fill.tolerance,
					      command->fill.antialias);
	    break;
	}
	case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
	{
	    cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs;
	    cairo_glyph_t *dev_glyphs;
	    int i, num_glyphs = command->show_text_glyphs.num_glyphs;

            /* 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.
	     */
	    dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
	    if (dev_glyphs == NULL) {
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
		break;
	    }

	    if (has_device_transform) {
		for (i = 0; i < num_glyphs; i++) {
		    dev_glyphs[i] = glyphs[i];
		    cairo_matrix_transform_point (device_transform,
						  &dev_glyphs[i].x,
						  &dev_glyphs[i].y);
		}
	    } else {
		memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
	    }

	    status = _cairo_surface_show_text_glyphs	(target,
							 command->show_text_glyphs.op,
							 &command->show_text_glyphs.source.base,
							 command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
							 dev_glyphs, num_glyphs,
							 command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
							 command->show_text_glyphs.cluster_flags,
							 command->show_text_glyphs.scaled_font);

	    free (dev_glyphs);
	    break;
	}
	case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
	    /* XXX Meta surface clipping is broken and requires some
	     * cairo-gstate.c rewriting.  Work around it for now. */
	    if (dev_path == NULL)
		_cairo_clip_reset (&clip);
	    else
		status = _cairo_clip_clip (&clip, dev_path,
					   command->intersect_clip_path.fill_rule,
					   command->intersect_clip_path.tolerance,
					   command->intersect_clip_path.antialias,
					   target);
	    break;
	default:
	    ASSERT_NOT_REACHED;
	}

	if (dev_path == &path_copy)
	    _cairo_path_fixed_fini (&path_copy);

	if (type == CAIRO_META_CREATE_REGIONS) {
	    if (status == CAIRO_STATUS_SUCCESS) {
		command->header.region = CAIRO_META_REGION_NATIVE;
	    } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
		command->header.region = CAIRO_META_REGION_IMAGE_FALLBACK;
		status = CAIRO_STATUS_SUCCESS;
	    }
	}

	if (status)
	    break;
    }

    _cairo_clip_reset (&clip);
    status2 = _cairo_surface_set_clip (target, old_clip);
    if (status == CAIRO_STATUS_SUCCESS)
	status = status2;

    return _cairo_surface_set_error (surface, status);
}
static cairo_status_t
_cairo_pdf_operators_emit_glyph (cairo_pdf_operators_t             *pdf_operators,
				 cairo_glyph_t              	   *glyph,
				 cairo_scaled_font_subsets_glyph_t *subset_glyph)
{
    double x, y;
    cairo_status_t status;

    if (pdf_operators->is_new_text_object ||
	pdf_operators->font_id != subset_glyph->font_id ||
	pdf_operators->subset_id != subset_glyph->subset_id)
    {
	status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
	if (unlikely (status))
	    return status;

	status = _cairo_pdf_operators_set_font_subset (pdf_operators, subset_glyph);
	if (unlikely (status))
	    return status;

	pdf_operators->is_new_text_object = FALSE;
    }

    x = glyph->x;
    y = glyph->y;
    cairo_matrix_transform_point (&pdf_operators->cairo_to_pdftext, &x, &y);

    /* The TJ operator for displaying text strings can only set
     * the horizontal position of the glyphs. If the y position
     * (in text space) changes, use the Td operator to change the
     * current position to the next glyph. We also use the Td
     * operator to move the current position if the horizontal
     * position changes by more than 10 (in text space
     * units). This is becauses the horizontal glyph positioning
     * in the TJ operator is intended for kerning and there may be
     * PDF consumers that do not handle very large position
     * adjustments in TJ.
     */
    if (fabs(x - pdf_operators->glyph_buf_x_pos) > 10 ||
	fabs(y - pdf_operators->cur_y) > GLYPH_POSITION_TOLERANCE)
    {
	status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
	if (unlikely (status))
	    return status;

	x = glyph->x;
	y = glyph->y;
	cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y);
	status = _cairo_pdf_operators_set_text_position (pdf_operators, x, y);
	if (unlikely (status))
	    return status;

	x = 0.0;
	y = 0.0;
    }

    status = _cairo_pdf_operators_add_glyph (pdf_operators,
					     subset_glyph,
					     x);
    return status;
}
Beispiel #3
0
/**
 * \brief rotate an item by an @angle increment (may be negative)
 *
 * @angle the increment the item will be rotated (usually 90° steps)
 * @center_pos if rotated as part of a group, this is the center to rotate
 *around
 */
static void part_rotate (ItemData *data, int angle, Coords *center_pos)
{
	g_return_if_fail (data);
	g_return_if_fail (IS_PART (data));

	cairo_matrix_t morph, morph_rot, local_rot;
	Part *part;
	PartPriv *priv;
	gboolean handler_connected;
	// Coords b1, b2;

	part = PART (data);

	priv = part->priv;

	// FIXME store vanilla coords, apply the morph
	// FIXME to these and store the result in the
	// FIXME instance then everything will be fine
	// XXX also prevents rounding yiggle up downs

	angle /= 90;
	angle *= 90;

	cairo_matrix_init_rotate (&local_rot, (double)angle * M_PI / 180.);

	cairo_matrix_multiply (item_data_get_rotate (data), item_data_get_rotate (data), &local_rot);

	morph_rot = *(item_data_get_rotate (data));

	cairo_matrix_multiply (&morph, &morph_rot, item_data_get_translate (data));

	Coords delta_to_center, delta_to_center_transformed;
	Coords delta_to_apply, delta_bbox;
	Coords bbox_center, bbox_center_transformed;
	Coords item_pos;

// get bbox
#if 0 // this causes #115 to reappear
	item_data_get_relative_bbox (ITEM_DATA (part), &b1, &b2);
	bbox_center = coords_average (&b1, &b2);
#endif
	item_data_get_pos (ITEM_DATA (part), &item_pos);

	Coords rotation_center;

	if (center_pos == NULL) {
		rotation_center = coords_sum (&bbox_center, &item_pos);
	} else {
		rotation_center = *center_pos;
	}

	delta_to_center_transformed = delta_to_center = coords_sub (&rotation_center, &item_pos);
	cairo_matrix_transform_point (&local_rot, &(delta_to_center_transformed.x),
	                              &(delta_to_center_transformed.y));

	delta_to_apply = coords_sub (&delta_to_center, &delta_to_center_transformed);

#define DEBUG_THIS 0
	// use the cairo matrix funcs to transform the pin
	// positions relative to the item center
	// this is only indirectly related to displayin
	// HINT: we need to modify the actual pins to make the
	// pin tests work being used to detect connections

	gint i;
	gdouble x, y;
	// Rotate the pins.
	for (i = 0; i < priv->num_pins; i++) {
		x = priv->pins_orig[i].offset.x;
		y = priv->pins_orig[i].offset.y;
		cairo_matrix_transform_point (&morph_rot, &x, &y);

		if (fabs (x) < 1e-2)
			x = 0.0;
		if (fabs (y) < 1e-2)
			y = 0.0;

		priv->pins[i].offset.x = x;
		priv->pins[i].offset.y = y;
	}

	item_data_move (data, &delta_to_apply);

	handler_connected = g_signal_handler_is_connected (G_OBJECT (data), data->changed_handler_id);
	if (handler_connected) {
		g_signal_emit_by_name (G_OBJECT (data), "changed");
	} else {
		NG_DEBUG ("handler not yet registerd.");
	}
	NG_DEBUG ("\n\n");
}
Beispiel #4
0
/**
 * flip a part in a given direction
 * @direction gives the direction the item will be flipped, end users pov!
 * @center the center to flip over - currently ignored FIXME
 */
static void part_flip (ItemData *data, IDFlip direction, Coords *center)
{
#if 0
	Part *part;
	PartPriv *priv;
	int i;
	cairo_matrix_t affine;
	double x, y;
	double scale_v, scale_h;
	gboolean handler_connected;
	Coords delta;
	Coords pos, trans;
	Coords b1, b2;
	Coords pos_new, pos_old;
	//FIXME properly recenter after flipping
	//Coords part_center_before, part_center_after, delta;

	g_return_if_fail (data);
	g_return_if_fail (IS_PART (data));

	part = PART (data);
	priv = part->priv;

	item_data_get_pos (data, &trans);

	// mask, just for the sake of cleanness
	direction &= ID_FLIP_MASK;

	// TODO evaluate if we really want to be able to do double flips (180* rots via flipping)
	g_assert (direction != ID_FLIP_MASK);


	// create a transformation _relativ_ to the current _state_
	// reverse axis and fix the created offset by adding 2*pos.x or .y

	// convert the flip direction to binary, used in the matrix setup
	// keep in mind that we do relativ manipulations within the model
	// which in turn makes this valid for all rotations!
	scale_h = ((direction & ID_FLIP_HORIZ) != 0) ? -1. : 1.;
	scale_v = ((direction & ID_FLIP_VERT) != 0) ? -1. : 1.;

	// magic, if we are in either 270 or 90 state, we need to rotate the flip state by 90° to draw it properly
	// TODO maybe better put this into the rotation function
	if ((priv->rotation / 90) % 2 == 1) {
		priv->flip ^= ID_FLIP_MASK;
	}
	// toggle the direction
	priv->flip ^= direction;
	if ((priv->flip & ID_FLIP_MASK)== ID_FLIP_MASK) {
		priv->flip = ID_FLIP_NONE;
		priv->rotation += 180;
		priv->rotation %= 360;
	}

	cairo_matrix_init_scale (&affine, scale_h, scale_v);

	item_data_get_pos (data, &pos_old);
	pos_new = pos_old;
	cairo_matrix_transform_point (&affine, &pos_new.x, &pos_new.y);

	g_printf ("\ncenter %p [old] x=%lf,y=%lf -->", data, pos_old.x, pos_old.y);
	g_printf ("  x=%lf, y=%lf\n", pos_new.x, pos_new.y);
	delta.x = - pos_new.x + pos_old.x;
	delta.y = - pos_new.y + pos_old.y;

	// flip the pins
	for (i = 0; i < priv->num_pins; i++) {

		x = priv->pins[i].offset.x;
		y = priv->pins[i].offset.y;
		cairo_matrix_transform_point (&affine, &x, &y);

		if (fabs (x) < 1e-2)
			x = 0.0;
		if (fabs (y) < 1e-2)
			y = 0.0;

		priv->pins[i].offset.x = x;
		priv->pins[i].offset.y = y;
	}
	item_data_snap (data);

	// tell the view
	handler_connected = g_signal_handler_is_connected (G_OBJECT (part),
	                                                   ITEM_DATA(part)->flipped_handler_id);
	if (handler_connected) {
		g_signal_emit_by_name (G_OBJECT (part), "flipped", priv->flip);

		// TODO - proper boundingbox center calculation

		item_data_get_relative_bbox (ITEM_DATA (part), &b1, &b2);

		// flip the bounding box.
		cairo_matrix_transform_point (&affine, &b1.x, &b1.y);
		cairo_matrix_transform_point (&affine, &b2.x, &b2.y);

		item_data_set_relative_bbox (ITEM_DATA (part), &b1, &b2);
		item_data_set_pos (ITEM_DATA (part), &pos);

		// FIXME - proper recenter to boundingbox center
	}
	if (g_signal_handler_is_connected (G_OBJECT (part),
	                                   ITEM_DATA (part)->changed_handler_id)) {
		g_signal_emit_by_name (G_OBJECT (part),
		                       "changed");
	}
#endif
}
Beispiel #5
0
/**
 * Drawing: giza_vector
 *
 * Synopsis: Plot of vector data.
 *
 * Input:
 *  -n             :- The dimensions of data in the x-direction
 *  -m             :- The dimensions of data in the y-direction
 *  -horizontal    :- The x-component of the data to be plotted
 *  -vertical      :- The y-component of the data to be plotted
 *  -i1            :- The inclusive range of data to render in the x dimension.
 *  -i2            :- The inclusive range of data to render in the x dimension.
 *  -j1            :- The inclusive range of data to render in the y direction
 *  -j2            :- The inclusive range of data to render in the y direction
 *  -scale         :- scaling factor for arrow lengths (0 = automatic)
 *  -position      :- justification of vector arrow with respect to pixel (0=left, 0.5=centred)
 *  -affine        :- The affine transformation matrix that will be applied to the data.
 *
 * See Also: giza_vector_float, giza_arrow, giza_set_arrow_style
 */
void
giza_vector (int n, int m, const double* horizontal, const double* vertical,
	     int i1, int i2, int j1, int j2, double scale, int position,
	     const double* affine, double blank)
{
  if (!_giza_check_device_ready ("giza_vector"))
    return;

  /* Check ranges */
  if (i1 < 0 || i2 >= n || i1 > i2)
    {
      _giza_error ("giza_vector",
		   "invalid index range for horizontal values");
      return;
    }
  if (j1 < 0 || j2 >= m || j1 > j2)
    {
      _giza_error ("giza_vector", "invalid index range for vertical values");
      return;
    }

  int i, j;
  double x1, x2, y1, y2;
  cairo_matrix_t mat;

  cairo_matrix_init (&mat, affine[0], affine[1], affine[2], affine[3],
                     affine[4], affine[5]);

  double dscale = scale;
  /* Find the scaling factor */
  if (fabs (dscale) < GIZA_ZERO_DOUBLE)
    {
      for (j = j1; j <= j2; j++)
	{
	  for (i = i1; i <= i2; i++)
	    {
	      if (!(_giza_equal(horizontal[j*n+i],blank) && _giza_equal(vertical[j*n+i],blank)))
		{
		  double tmp =
		    sqrt (horizontal[j*n+i] * horizontal[j*n+i] +
			  vertical[j*n+i] * vertical[j*n+i]);
		  if (tmp > dscale)
		    dscale = tmp;
		}
	    }
	}
      if (fabs (dscale) < GIZA_ZERO_DOUBLE) { return; }
      double dx2 = affine[0]*affine[0] + affine[1]*affine[1];
      double dy2 = affine[2]*affine[2] + affine[3]*affine[3];
      if (dx2 < dy2)
        {
          dscale = sqrt(dx2)/dscale;
        } else {
          dscale = sqrt(dy2)/dscale;
        }
    }

  int oldBuf;
  giza_get_buffering(&oldBuf);
  giza_begin_buffer ();

 /* Draw the arrows! */
  double x, y;
  for (j = j1; j <= j2; j++)
    {
      for (i = i1; i <= i2; i++)
	{
	  if (!(_giza_equal(horizontal[j*n+i],blank) && _giza_equal(vertical[j*n+i],blank)))
          {
             x = (double) i + 0.5;
             y = (double) j + 0.5;
 	     cairo_matrix_transform_point (&mat, &x, &y);

	     if (position < 0)
	       {
	         x2 = x;
	         y2 = y;
	         x1 = x2 - horizontal[j*n+i] * dscale;
	         y1 = y2 - vertical[j*n+i] * dscale;
	       }
	     else if (_giza_equal(position,0.))
	       {
	         x2 = x + 0.5 * horizontal[j*n+i] * dscale;
	         y2 = y + 0.5 * vertical[j*n+i] * dscale;
	         x1 = x2 - horizontal[j*n+i] * dscale;
	         y1 = y2 - vertical[j*n+i] * dscale;
	       }
	     else
	       {
	         x1 = x;
	         y1 = y;
	         x2 = x1 + horizontal[j*n+i] * dscale;
	         y2 = y1 + vertical[j*n+i] * dscale;
	       }
	     giza_arrow (x1, y1, x2, y2);
	 }
       }
    }

  if (!oldBuf)
    giza_end_buffer ();

  giza_flush_device ();
}
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);
}
cairo_warn cairo_int_status_t
_cairo_dwrite_scaled_show_glyphs(void			*scaled_font,
				 cairo_operator_t	 op,
				 const cairo_pattern_t	*pattern,
				 cairo_surface_t	*generic_surface,
				 int			 source_x,
				 int			 source_y,
				 int			 dest_x,
				 int			 dest_y,
				 unsigned int		 width,
				 unsigned int		 height,
				 cairo_glyph_t		*glyphs,
				 int			 num_glyphs,
				 cairo_region_t		*clip_region,
				 int			*remaining_glyphs)
{
    cairo_win32_surface_t *surface = (cairo_win32_surface_t *)generic_surface;
    cairo_int_status_t status;

    if (width == 0 || height == 0)
	return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;

    if (_cairo_surface_is_win32 (generic_surface) &&
	surface->format == CAIRO_FORMAT_RGB24 &&
	op == CAIRO_OPERATOR_OVER) {

	    //XXX: we need to set the clip region here

	status = (cairo_int_status_t)_cairo_dwrite_show_glyphs_on_surface (surface, op, pattern,
									  glyphs, num_glyphs, 
									  (cairo_scaled_font_t*)scaled_font, NULL);

	return status;
    } else {
	cairo_dwrite_scaled_font_t *dwritesf =
	    static_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
	UINT16 *indices = new UINT16[num_glyphs];
	DWRITE_GLYPH_OFFSET *offsets = new DWRITE_GLYPH_OFFSET[num_glyphs];
	FLOAT *advances = new FLOAT[num_glyphs];
	BOOL transform = FALSE;

	DWRITE_GLYPH_RUN run;
	run.bidiLevel = 0;
	run.fontFace = ((cairo_dwrite_font_face_t*)dwritesf->base.font_face)->dwriteface;
	run.glyphIndices = indices;
	run.glyphCount = num_glyphs;
	run.isSideways = FALSE;
	run.glyphOffsets = offsets;
	run.glyphAdvances = advances;
    	IDWriteGlyphRunAnalysis *analysis;

	if (dwritesf->mat.xy == 0 && dwritesf->mat.yx == 0 &&
	    dwritesf->mat.xx == dwritesf->base.font_matrix.xx && 
	    dwritesf->mat.yy == dwritesf->base.font_matrix.yy) {

	    for (int i = 0; i < num_glyphs; i++) {
		indices[i] = (WORD) glyphs[i].index;
		// Since we will multiply by our ctm matrix later for rotation effects
		// and such, adjust positions by the inverse matrix now.
		offsets[i].ascenderOffset = (FLOAT)dest_y - (FLOAT)glyphs[i].y;
		offsets[i].advanceOffset = (FLOAT)glyphs[i].x - dest_x;
		advances[i] = 0.0;
	    }
	    run.fontEmSize = (FLOAT)dwritesf->base.font_matrix.yy;
	} else {
	    transform = TRUE;

	    for (int i = 0; i < num_glyphs; i++) {
		indices[i] = (WORD) glyphs[i].index;
		double x = glyphs[i].x - dest_x;
		double y = glyphs[i].y - dest_y;
		cairo_matrix_transform_point(&dwritesf->mat_inverse, &x, &y);
		// Since we will multiply by our ctm matrix later for rotation effects
		// and such, adjust positions by the inverse matrix now.
		offsets[i].ascenderOffset = -(FLOAT)y;
		offsets[i].advanceOffset = (FLOAT)x;
		advances[i] = 0.0;
	    }
	    run.fontEmSize = 1.0f;
	}

	if (!transform) {
	    DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run,
							      1.0f,
							      NULL,
							      DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC,
							      DWRITE_MEASURING_MODE_NATURAL,
							      0,
							      0,
							      &analysis);
	} else {
	    DWRITE_MATRIX dwmatrix = _cairo_dwrite_matrix_from_matrix(&dwritesf->mat);
	    DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run,
							      1.0f,
							      &dwmatrix,
							      DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC,
							      DWRITE_MEASURING_MODE_NATURAL,
							      0,
							      0,
							      &analysis);
	}

	RECT r;
	r.left = 0;
	r.top = 0;
	r.right = width;
	r.bottom = height;

	BYTE *surface = new BYTE[width * height * 3];

	analysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, &r, surface, width * height * 3);

	cairo_image_surface_t *mask_surface = 
	    (cairo_image_surface_t*)cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);

	cairo_surface_flush(&mask_surface->base);

	for (unsigned int y = 0; y < height; y++) {
	    for (unsigned int x = 0; x < width; x++) {
		mask_surface->data[y * mask_surface->stride + x * 4] = surface[y * width * 3 + x * 3 + 1];
		mask_surface->data[y * mask_surface->stride + x * 4 + 1] = surface[y * width * 3 + x * 3 + 1];
		mask_surface->data[y * mask_surface->stride + x * 4 + 2] = surface[y * width * 3 + x * 3 + 1];
		mask_surface->data[y * mask_surface->stride + x * 4 + 3] = surface[y * width * 3 + x * 3 + 1];
	    }
	}
	cairo_surface_mark_dirty(&mask_surface->base);

	pixman_image_set_component_alpha(mask_surface->pixman_image, 1);

	cairo_surface_pattern_t mask;
	_cairo_pattern_init_for_surface (&mask, &mask_surface->base);

	status = (cairo_int_status_t)_cairo_surface_composite (op, pattern,
							       &mask.base,
							       generic_surface,
							       source_x, source_y,
							       0, 0,
							       dest_x, dest_y,
							       width, height,
							       clip_region);

	_cairo_pattern_fini (&mask.base);

	analysis->Release();
	delete [] surface;
	delete [] indices;
	delete [] offsets;
	delete [] advances;

	cairo_surface_destroy (&mask_surface->base);
	*remaining_glyphs = 0;

	return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
    }
}
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,
        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_clip_t		    *clip)
{
    cairo_status_t status;
    cairo_clip_t clip_copy, *dev_clip = clip;
    cairo_glyph_t *dev_glyphs = glyphs;
    cairo_pattern_union_t source_copy;
    cairo_clip_t target_clip;

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

    if (glyphs == NULL || num_glyphs == 0)
        return CAIRO_STATUS_SUCCESS;

    if (wrapper->has_extents) {
        _cairo_clip_init_copy (&target_clip, clip);
        status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
        if (unlikely (status))
            goto FINISH;

        dev_clip = clip = &target_clip;
    }

    if (clip && clip->all_clipped) {
        status = CAIRO_STATUS_SUCCESS;
        goto FINISH;
    }

    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
            _cairo_surface_wrapper_needs_extents_transform (wrapper))
    {
        cairo_matrix_t m;
        int i;

        cairo_matrix_init_identity (&m);

        if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
            cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);

        if (_cairo_surface_wrapper_needs_device_transform (wrapper))
            cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);

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

            dev_clip = &clip_copy;
        }

        dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
        if (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 (clip != NULL) {
            dev_clip = &clip_copy;
            _cairo_clip_init_copy (&clip_copy, clip);
        }
    }

    status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
             utf8, utf8_len,
             dev_glyphs, num_glyphs,
             clusters, num_clusters,
             cluster_flags,
             scaled_font,
             dev_clip);

FINISH:
    if (dev_clip != clip)
        _cairo_clip_reset (dev_clip);
    if (wrapper->has_extents)
        _cairo_clip_reset (&target_clip);
    if (dev_glyphs != glyphs)
        free (dev_glyphs);
    return status;
}
Beispiel #9
0
/*
 * Convert a gerber image to a GDK clip mask to be used when creating pixmap
 */
int
draw_gdk_image_to_pixmap(GdkPixmap **pixmap, gerbv_image_t *image, 
	     double scale, double trans_x, double trans_y,
	     gchar drawMode,
	     gerbv_selection_info_t *selectionInfo, gerbv_render_info_t *renderInfo,
	     gerbv_user_transformation_t transform)
{
	GdkGC *gc = gdk_gc_new(*pixmap);
	GdkGC *pgc = gdk_gc_new(*pixmap);
	GdkGCValues gc_values;
	struct gerbv_net *net;
	gerbv_netstate_t *oldState;
	gerbv_layer_t *oldLayer;
	gint x1, y1, x2, y2;
	glong xlong1, ylong1, xlong2, ylong2;
	int p1, p2;
	int cir_width = 0, cir_height = 0;
	int cp_x = 0, cp_y = 0;
	GdkColor transparent, opaque;
	gerbv_polarity_t polarity;
	gdouble tempX,tempY;
	gdouble minX=0,minY=0,maxX=0,maxY=0;

	if (transform.inverted) {
		if (image->info->polarity == GERBV_POLARITY_POSITIVE)
			polarity = GERBV_POLARITY_NEGATIVE;
		else
			polarity = GERBV_POLARITY_POSITIVE;
	} else {
		polarity = image->info->polarity;
	}
	if (drawMode == DRAW_SELECTIONS)
		polarity = GERBV_POLARITY_POSITIVE;

	gboolean useOptimizations = TRUE;
	// if the user is using any transformations for this layer, then don't bother using rendering
	//   optimizations
	if ((fabs(transform.translateX) > 0.00001) ||
			(fabs(transform.translateY) > 0.00001) ||
			(fabs(transform.scaleX - 1) > 0.00001) ||
			(fabs(transform.scaleY - 1) > 0.00001) ||
			(fabs(transform.rotation) > 0.00001) ||
			transform.mirrorAroundX || transform.mirrorAroundY)
		useOptimizations = FALSE;

	// calculate the transformation matrix for the user_transformation options
	cairo_matrix_t fullMatrix, scaleMatrix;
	cairo_matrix_init (&fullMatrix, 1, 0, 0, 1, 0, 0);
	cairo_matrix_init (&scaleMatrix, 1, 0, 0, 1, 0, 0);

	cairo_matrix_translate (&fullMatrix, trans_x, trans_y);
	cairo_matrix_scale (&fullMatrix, scale, scale);
	cairo_matrix_scale (&scaleMatrix, scale, scale);
	/* offset image */

	cairo_matrix_translate (&fullMatrix, transform.translateX, -1*transform.translateY);
	// don't use mirroring for the scale matrix
	gdouble scaleX = transform.scaleX;
	gdouble scaleY = -1*transform.scaleY;
	cairo_matrix_scale (&scaleMatrix, scaleX, -1*scaleY);
	if (transform.mirrorAroundX)
		scaleY *= -1;
	if (transform.mirrorAroundY)
		scaleX *= -1;

	cairo_matrix_scale (&fullMatrix, scaleX, scaleY);
	/* do image rotation */
	cairo_matrix_rotate (&fullMatrix, transform.rotation);
	//cairo_matrix_rotate (&scaleMatrix, transform.rotation);

	/* do image rotation */
	cairo_matrix_rotate (&fullMatrix, image->info->imageRotation);

	if (useOptimizations) {
		minX = renderInfo->lowerLeftX;
		minY = renderInfo->lowerLeftY;
		maxX = renderInfo->lowerLeftX + (renderInfo->displayWidth /
					renderInfo->scaleFactorX);
		maxY = renderInfo->lowerLeftY + (renderInfo->displayHeight /
					renderInfo->scaleFactorY);
	}

	if (image == NULL || image->netlist == NULL) {
		/*
		 * Destroy GCs before exiting
		 */
		gdk_gc_unref(gc);
		gdk_gc_unref(pgc);

		return 0;
	}

	/* Set up the two "colors" we have */
	opaque.pixel = 0; /* opaque will not let color through */
	transparent.pixel = 1; /* transparent will let color through */ 

	/*
	* Clear clipmask and set draw color depending image on image polarity
	*/
	if (polarity == GERBV_POLARITY_NEGATIVE) {
		gdk_gc_set_foreground(gc, &transparent);
		gdk_draw_rectangle(*pixmap, gc, TRUE, 0, 0, -1, -1);
		gdk_gc_set_foreground(gc, &opaque);
	} else {
		gdk_gc_set_foreground(gc, &opaque);
		gdk_draw_rectangle(*pixmap, gc, TRUE, 0, 0, -1, -1);
		gdk_gc_set_foreground(gc, &transparent);
	}
	oldLayer = image->layers;
	oldState = image->states;
	for (net = image->netlist->next ; net != NULL; net = gerbv_image_return_next_renderable_object(net)) {
		int repeat_X=1, repeat_Y=1;
		double repeat_dist_X=0.0, repeat_dist_Y=0.0;
		int repeat_i, repeat_j;

		/*
		 * If step_and_repeat (%SR%) used, repeat the drawing;
		 */
		repeat_X = net->layer->stepAndRepeat.X;
		repeat_Y = net->layer->stepAndRepeat.Y;
		repeat_dist_X = net->layer->stepAndRepeat.dist_X;
		repeat_dist_Y = net->layer->stepAndRepeat.dist_Y;

		/* check if this is a new netstate */
		if (net->state != oldState){
			/* it's a new state, so recalculate the new transformation matrix
			   for it */
			draw_gdk_apply_netstate_transformation (&fullMatrix, &scaleMatrix, net->state);
			oldState = net->state;	
		}
		/* check if this is a new layer */
		/* for now, only do layer rotations in GDK rendering */
		if (net->layer != oldLayer){
			cairo_matrix_rotate (&fullMatrix, net->layer->rotation);
			oldLayer = net->layer;
		}

		if (drawMode == DRAW_SELECTIONS) {
			int i;
			gboolean foundNet = FALSE;
			
			for (i=0; i<selectionInfo->selectedNodeArray->len; i++){
				gerbv_selection_item_t sItem = g_array_index (selectionInfo->selectedNodeArray,
					gerbv_selection_item_t, i);
				if (sItem.net == net)
					foundNet = TRUE;
			}
			if (!foundNet)
				continue;
		}

		for(repeat_i = 0; repeat_i < repeat_X; repeat_i++) {
		for(repeat_j = 0; repeat_j < repeat_Y; repeat_j++) {
		  double sr_x = repeat_i * repeat_dist_X;
		  double sr_y = repeat_j * repeat_dist_Y;
			
			if ((useOptimizations)&&((net->boundingBox.right+sr_x < minX)
					|| (net->boundingBox.left+sr_x > maxX)
					|| (net->boundingBox.top+sr_y < minY)
					|| (net->boundingBox.bottom+sr_y > maxY))) {
				continue;
			}

		/* 
		 * If circle segment, scale and translate that one too
		 */
		if (net->cirseg) {
		    tempX = net->cirseg->width;
		    tempY = net->cirseg->height;
		    cairo_matrix_transform_point (&scaleMatrix, &tempX, &tempY);
		    cir_width = (int)round(tempX);
		    cir_height = (int)round(tempY);
		    
		    tempX = net->cirseg->cp_x;
		    tempY = net->cirseg->cp_y;
		    cairo_matrix_transform_point (&fullMatrix, &tempX, &tempY);
		    cp_x = (int)round(tempX);
		    cp_y = (int)round(tempY);
		}

		/*
		 * Set GdkFunction depending on if this (gerber) layer is inverted
		 * and allow for the photoplot being negative.
		 */
		gdk_gc_set_function(gc, GDK_COPY);
		if ((net->layer->polarity == GERBV_POLARITY_CLEAR) != (polarity == GERBV_POLARITY_NEGATIVE))
		    gdk_gc_set_foreground(gc, &opaque);
		else
		    gdk_gc_set_foreground(gc, &transparent);

		/*
		 * Polygon Area Fill routines
		 */
		switch (net->interpolation) {
		case GERBV_INTERPOLATION_PAREA_START :
		    draw_gdk_render_polygon_object (net,image,sr_x,sr_y,&fullMatrix,
		    	&scaleMatrix,gc,pgc,pixmap);
		    continue;
		/* make sure we completely skip over any deleted nodes */
		case GERBV_INTERPOLATION_DELETED:
		    continue;
		default :
		    break;
		}


		/*
		 * If aperture state is off we allow use of undefined apertures.
		 * This happens when gerber files starts, but hasn't decided on 
		 * which aperture to use.
		 */
		if (image->aperture[net->aperture] == NULL) {
		  /* Commenting this out since it gets emitted every time you click on the screen 
		     if (net->aperture_state != GERBV_APERTURE_STATE_OFF)
		     GERB_MESSAGE("Aperture D%d is not defined\n", net->aperture);
		  */
		    continue;
		}

		/*
		 * Scale points with window scaling and translate them
		 */
		tempX = net->start_x + sr_x;
		tempY = net->start_y + sr_y;
		cairo_matrix_transform_point (&fullMatrix, &tempX, &tempY);
		xlong1 = (int)round(tempX);
		ylong1 = (int)round(tempY);

		tempX = net->stop_x + sr_x;
		tempY = net->stop_y + sr_y;
		cairo_matrix_transform_point (&fullMatrix, &tempX, &tempY);
		xlong2 = (int)round(tempX);
		ylong2 = (int)round(tempY);

		/* if the object is way outside our view window, just skip over it in order
		   to eliminate some GDK clipping problems at high zoom levels */
		if ((xlong1 < -10000) && (xlong2 < -10000))
			continue;
		if ((ylong1 < -10000) && (ylong2 < -10000))
			continue;
		if ((xlong1 > 10000) && (xlong2 > 10000))
			continue;
		if ((ylong1 > 10000) && (ylong2 > 10000))
			continue;

		if (xlong1 > G_MAXINT) x1 = G_MAXINT;
		else if (xlong1 < G_MININT) x1 = G_MININT;
		else x1 = (int)xlong1;

		if (xlong2 > G_MAXINT) x2 = G_MAXINT;
		else if (xlong2 < G_MININT) x2 = G_MININT;
		else x2 = (int)xlong2;

		if (ylong1 > G_MAXINT) y1 = G_MAXINT;
		else if (ylong1 < G_MININT) y1 = G_MININT;
		else y1 = (int)ylong1;

		if (ylong2 > G_MAXINT) y2 = G_MAXINT;
		else if (ylong2 < G_MININT) y2 = G_MININT;
		else y2 = (int)ylong2;
			
		switch (net->aperture_state) {
		case GERBV_APERTURE_STATE_ON :
		    tempX = image->aperture[net->aperture]->parameter[0];
		    cairo_matrix_transform_point (&scaleMatrix, &tempX, &tempY);
		    p1 = (int)round(tempX);

		   // p1 = (int)round(image->aperture[net->aperture]->parameter[0] * scale);
		    if (image->aperture[net->aperture]->type == GERBV_APTYPE_RECTANGLE)
			gdk_gc_set_line_attributes(gc, p1, 
						   GDK_LINE_SOLID, 
						   GDK_CAP_PROJECTING, 
						   GDK_JOIN_MITER);
		    else
			gdk_gc_set_line_attributes(gc, p1, 
						   GDK_LINE_SOLID, 
						   GDK_CAP_ROUND, 
						   GDK_JOIN_MITER);
		    
		    switch (net->interpolation) {
		    case GERBV_INTERPOLATION_x10 :
		    case GERBV_INTERPOLATION_LINEARx01 :
		    case GERBV_INTERPOLATION_LINEARx001 :
			GERB_MESSAGE(_("Linear != x1\n"));
			gdk_gc_set_line_attributes(gc, p1, 
						   GDK_LINE_ON_OFF_DASH, 
						   GDK_CAP_ROUND, 
						   GDK_JOIN_MITER);
			gdk_draw_line(*pixmap, gc, x1, y1, x2, y2);
			gdk_gc_set_line_attributes(gc, p1, 
						   GDK_LINE_SOLID,
						   GDK_CAP_ROUND, 
						   GDK_JOIN_MITER);
			break;
		    case GERBV_INTERPOLATION_LINEARx1 :
			if (image->aperture[net->aperture]->type != GERBV_APTYPE_RECTANGLE)
			    gdk_draw_line(*pixmap, gc, x1, y1, x2, y2);
			else {
			    gint dx, dy;
			    GdkPoint poly[6];
			    
			    tempX = image->aperture[net->aperture]->parameter[0]/2;
			    tempY = image->aperture[net->aperture]->parameter[1]/2;
			    cairo_matrix_transform_point (&scaleMatrix, &tempX, &tempY);
			    dx = (int)round(tempX);
			    dy = (int)round(tempY);

			    if(x1 > x2) dx = -dx;
			    if(y1 > y2) dy = -dy;
			    poly[0].x = x1 - dx; poly[0].y = y1 - dy;
			    poly[1].x = x1 - dx; poly[1].y = y1 + dy;
			    poly[2].x = x2 - dx; poly[2].y = y2 + dy;
			    poly[3].x = x2 + dx; poly[3].y = y2 + dy;
			    poly[4].x = x2 + dx; poly[4].y = y2 - dy;
			    poly[5].x = x1 + dx; poly[5].y = y1 - dy;
			    gdk_draw_polygon(*pixmap, gc, 1, poly, 6);
			}
				break;
		    case GERBV_INTERPOLATION_CW_CIRCULAR :
		    case GERBV_INTERPOLATION_CCW_CIRCULAR :
			gerbv_gdk_draw_arc(*pixmap, gc, cp_x, cp_y, cir_width, cir_height, 
					   net->cirseg->angle1, net->cirseg->angle2);
			break;
		    default :
			break;
		    }
		    break;
		case GERBV_APERTURE_STATE_OFF :
		    break;
		case GERBV_APERTURE_STATE_FLASH :
		    tempX = image->aperture[net->aperture]->parameter[0];
		    tempY = image->aperture[net->aperture]->parameter[1];
		    cairo_matrix_transform_point (&scaleMatrix, &tempX, &tempY);
		    p1 = (int)round(tempX);
		    p2 = (int)round(tempY);
		    tempX = image->aperture[net->aperture]->parameter[2];
		    cairo_matrix_transform_point (&scaleMatrix, &tempX, &tempY);
		    
		    switch (image->aperture[net->aperture]->type) {
		    case GERBV_APTYPE_CIRCLE :
			gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p1);
			/*
			 * If circle has an inner diameter we must remove
			 * that part of the circle to make a hole in it.
			 * We should actually support square holes too,
			 * but due to laziness I don't.
			 */
			if (p2) {
			    gdk_gc_get_values(gc, &gc_values);
			    if (gc_values.foreground.pixel == opaque.pixel) {
				gdk_gc_set_foreground(gc, &transparent);
				gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p2);
				gdk_gc_set_foreground(gc, &opaque);
			    } else {
				gdk_gc_set_foreground(gc, &opaque);
				gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p2);
				gdk_gc_set_foreground(gc, &transparent);
			    }
			}

			break;
		    case GERBV_APTYPE_RECTANGLE:
			gerbv_gdk_draw_rectangle(*pixmap, gc, TRUE, x2, y2, p1, p2);
			break;
		    case GERBV_APTYPE_OVAL :
			gerbv_gdk_draw_oval(*pixmap, gc, TRUE, x2, y2, p1, p2);
			break;
		    case GERBV_APTYPE_POLYGON :
			gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p1);
			break;
		    case GERBV_APTYPE_MACRO :
			gerbv_gdk_draw_amacro(*pixmap, gc, 
					      image->aperture[net->aperture]->simplified,
					      scale, x2, y2);
			break;
		    default :
			GERB_MESSAGE(_("Unknown aperture type\n"));
			return 0;
		    }
		    break;
		default :
		    GERB_MESSAGE(_("Unknown aperture state\n"));
		    return 0;
		}
		}
		}
	}
	/*
	* Destroy GCs before exiting
	*/
	gdk_gc_unref(gc);
	gdk_gc_unref(pgc);

	return 1;

} /* image2pixmap */
Beispiel #10
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 (&m)) {
	    cairo_matrix_t ctm;

	    _cairo_matrix_multiply (&ctm,
				    &m,
				    &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;
}
Beispiel #11
0
void
draw_gdk_render_polygon_object (gerbv_net_t *oldNet, gerbv_image_t *image, double sr_x, double sr_y,
			cairo_matrix_t *fullMatrix, cairo_matrix_t *scaleMatrix, GdkGC *gc, GdkGC *pgc,
			GdkPixmap **pixmap) {
	gerbv_net_t *currentNet;
	gint x2,y2,cp_x=0,cp_y=0,cir_width=0;
	GdkPoint *points = NULL;
	int pointArraySize=0;
	int curr_point_idx = 0;
	int steps,i;
	gdouble angleDiff, tempX, tempY;

	/* save the first net in the polygon as the "ID" net pointer
	in case we are saving this net to the selection array */
	curr_point_idx = 0;
	pointArraySize = 0;

	for (currentNet = oldNet->next; currentNet!=NULL; currentNet = currentNet->next){	
		tempX = currentNet->stop_x + sr_x;
		tempY = currentNet->stop_y + sr_y;
		cairo_matrix_transform_point (fullMatrix, &tempX, &tempY);
		x2 = (int)round(tempX);
		y2 = (int)round(tempY);
		
		/* 
		* If circle segment, scale and translate that one too
		*/
		if (currentNet->cirseg) {
			tempX = currentNet->cirseg->width;
			tempY = currentNet->cirseg->height;
			cairo_matrix_transform_point (scaleMatrix, &tempX, &tempY);
			cir_width = (int)round(tempX);

			tempX = currentNet->cirseg->cp_x + sr_x;
			tempY = currentNet->cirseg->cp_y + sr_y;
			cairo_matrix_transform_point (fullMatrix, &tempX, &tempY);
			cp_x = (int)round(tempX);
			cp_y = (int)round(tempY);
		}

		switch (currentNet->interpolation) {
			case GERBV_INTERPOLATION_x10 :
			case GERBV_INTERPOLATION_LINEARx01 :
			case GERBV_INTERPOLATION_LINEARx001 :
			case GERBV_INTERPOLATION_LINEARx1 :
				if (pointArraySize < (curr_point_idx + 1)) {
					points = (GdkPoint *)g_realloc(points,sizeof(GdkPoint) *  (curr_point_idx + 1));
					pointArraySize = (curr_point_idx + 1);
				}
				points[curr_point_idx].x = x2;
				points[curr_point_idx].y = y2;
				curr_point_idx++;
				break;
			case GERBV_INTERPOLATION_CW_CIRCULAR :
			case GERBV_INTERPOLATION_CCW_CIRCULAR :
				/* we need to chop up the arc into small lines for rendering
				with GDK */
				angleDiff = currentNet->cirseg->angle2 - currentNet->cirseg->angle1;
				steps = (int) abs(angleDiff);
				if (pointArraySize < (curr_point_idx + steps)) {
					points = (GdkPoint *)g_realloc(points,sizeof(GdkPoint) *  (curr_point_idx + steps));
					pointArraySize = (curr_point_idx + steps);
				}
				for (i=0; i<steps; i++){
					points[curr_point_idx].x = cp_x + cir_width / 2.0 * cos ((currentNet->cirseg->angle1 +
									      (angleDiff * i) / steps)*M_PI/180);
					points[curr_point_idx].y = cp_y - cir_width / 2.0 * sin ((currentNet->cirseg->angle1 +
									      (angleDiff * i) / steps)*M_PI/180);
					curr_point_idx++;
				}
				break;
			case GERBV_INTERPOLATION_PAREA_END :
				gdk_gc_copy(pgc, gc); 
				gdk_gc_set_line_attributes(pgc, 1, 
				       GDK_LINE_SOLID, 
				       GDK_CAP_PROJECTING, 
				       GDK_JOIN_MITER);
				gdk_draw_polygon(*pixmap, pgc, 1, points, curr_point_idx);
				g_free(points);
				points = NULL;
				return;
			default:
				break;
		}
	}
	return;
}
void
_cairo_matrix_to_pixman_matrix (const cairo_matrix_t	*matrix,
				pixman_transform_t	*pixman_transform,
				double xc,
				double yc)
{
    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;
	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_is_translation (matrix))
	    return;

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

        /* find the pattern space coordinate that maps to (xc, yc) */
	xc += .5; yc += .5; /* offset for the pixel centre */
	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 (! pixman_transform_point_3d (pixman_transform, &vector))
		return;

	    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)
		break;
	} while (--max_iterations);
    }
}
void
_cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
				      double *x1, double *y1,
				      double *x2, double *y2,
				      cairo_bool_t *is_tight)
{
    int i;
    double quad_x[4], quad_y[4];
    double min_x, max_x;
    double min_y, max_y;

    if (matrix->xy == 0. && matrix->yx == 0.) {
	/* non-rotation/skew matrix, just map the two extreme points */

	if (matrix->xx != 1.) {
	    quad_x[0] = *x1 * matrix->xx;
	    quad_x[1] = *x2 * matrix->xx;
	    if (quad_x[0] < quad_x[1]) {
		*x1 = quad_x[0];
		*x2 = quad_x[1];
	    } else {
		*x1 = quad_x[1];
		*x2 = quad_x[0];
	    }
	}
	if (matrix->x0 != 0.) {
	    *x1 += matrix->x0;
	    *x2 += matrix->x0;
	}

	if (matrix->yy != 1.) {
	    quad_y[0] = *y1 * matrix->yy;
	    quad_y[1] = *y2 * matrix->yy;
	    if (quad_y[0] < quad_y[1]) {
		*y1 = quad_y[0];
		*y2 = quad_y[1];
	    } else {
		*y1 = quad_y[1];
		*y2 = quad_y[0];
	    }
	}
	if (matrix->y0 != 0.) {
	    *y1 += matrix->y0;
	    *y2 += matrix->y0;
	}

	if (is_tight)
	    *is_tight = TRUE;

	return;
    }

    /* general matrix */
    quad_x[0] = *x1;
    quad_y[0] = *y1;
    cairo_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]);

    quad_x[1] = *x2;
    quad_y[1] = *y1;
    cairo_matrix_transform_point (matrix, &quad_x[1], &quad_y[1]);

    quad_x[2] = *x1;
    quad_y[2] = *y2;
    cairo_matrix_transform_point (matrix, &quad_x[2], &quad_y[2]);

    quad_x[3] = *x2;
    quad_y[3] = *y2;
    cairo_matrix_transform_point (matrix, &quad_x[3], &quad_y[3]);

    min_x = max_x = quad_x[0];
    min_y = max_y = quad_y[0];

    for (i=1; i < 4; i++) {
	if (quad_x[i] < min_x)
	    min_x = quad_x[i];
	if (quad_x[i] > max_x)
	    max_x = quad_x[i];

	if (quad_y[i] < min_y)
	    min_y = quad_y[i];
	if (quad_y[i] > max_y)
	    max_y = quad_y[i];
    }

    *x1 = min_x;
    *y1 = min_y;
    *x2 = max_x;
    *y2 = max_y;

    if (is_tight) {
        /* it's tight if and only if the four corner points form an axis-aligned
           rectangle.
           And that's true if and only if we can derive corners 0 and 3 from
           corners 1 and 2 in one of two straightforward ways...
           We could use a tolerance here but for now we'll fall back to FALSE in the case
           of floating point error.
        */
        *is_tight =
            (quad_x[1] == quad_x[0] && quad_y[1] == quad_y[3] &&
             quad_x[2] == quad_x[3] && quad_y[2] == quad_y[0]) ||
            (quad_x[1] == quad_x[3] && quad_y[1] == quad_y[0] &&
             quad_x[2] == quad_x[0] && quad_y[2] == quad_y[3]);
    }
}
void AffineTransform::map(double x, double y, double* x2, double* y2) const
{
    *x2 = x;
    *y2 = y;
    cairo_matrix_transform_point(&m_transform, x2, y2);
}
Beispiel #15
0
static void
user_to_device_point (cairo_skia_context_t *cr, double *x, double *y)
{
    cairo_matrix_transform_point (&cr->matrix, x, y);
    cairo_matrix_transform_point (&cr->target->image.base.device_transform, x, y);
}