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; }
/** * \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"); }
/** * 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 }
/** * 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; }
/* * 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 */
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; }
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); }
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); }