Esempio n. 1
0
GpStatus
pango_DrawString (GpGraphics *graphics, GDIPCONST WCHAR *stringUnicode, int length, GDIPCONST GpFont *font, GDIPCONST RectF *rc,
	GDIPCONST GpStringFormat *format, GpBrush *brush)
{
	PangoLayout *layout;
	RectF box;

	/* Setup cairo */
	if (brush) {
		gdip_brush_setup (graphics, brush);
	} else {
		cairo_set_source_rgb (graphics->ct, 0., 0., 0.);
	}

	cairo_save (graphics->ct);

	layout = gdip_pango_setup_layout (graphics, stringUnicode, length, font, rc, &box, format, NULL);
	if (!layout) {
		cairo_restore (graphics->ct);
		return OutOfMemory;
	}

	gdip_cairo_move_to (graphics, rc->X, rc->Y, FALSE, TRUE);
	pango_cairo_show_layout (graphics->ct, layout);

	g_object_unref (layout);
	cairo_restore (graphics->ct);
	return Ok;
}
Esempio n. 2
0
static GpStatus
DrawString (GpGraphics *graphics, GDIPCONST WCHAR *stringUnicode, int length, GDIPCONST GpFont *font, 
	GDIPCONST RectF *rc_org, GDIPCONST GpStringFormat *fmt, GpBrush *brush, 
	WCHAR *CleanString, GpStringDetailStruct* StringDetails, GpDrawTextData *data)
{
	float CursorX = 0.0;		/* Current X position of drawing cursor */
	float CursorY = 0.0;		/* Current Y position of drawing cursor */
	int StringLen = length;
	BOOL SetClipping = FALSE;
	unsigned long	i, j;
	int AlignHorz = data->align_horz;
	int AlignVert = data->align_vert;
	int LineHeight = data->line_height;
	int MaxY = data->max_y;
	cairo_font_extents_t FontExtent;
	RectF rect, *rc = ▭

	cairo_font_extents (graphics->ct, &FontExtent);

	if (OPTIMIZE_CONVERSION (graphics)) {
		rc->X = rc_org->X;
		rc->Y = rc_org->Y;
		rc->Width = rc_org->Width;
		rc->Height = rc_org->Height;
	} else {
		rc->X = gdip_unitx_convgr (graphics, rc_org->X);
		rc->Y = gdip_unity_convgr (graphics, rc_org->Y);
		rc->Width = gdip_unitx_convgr (graphics, rc_org->Width);
		rc->Height = gdip_unity_convgr (graphics, rc_org->Height);
	}

	/* Set our clipping rectangle */
	if ((rc->Width!=0) && (rc->Height!=0) && ((fmt->formatFlags & StringFormatFlagsNoClip)==0)) {
#ifdef DRAWSTRING_DEBUG
		printf("Setting clipping rectangle (%f, %f %fx%f)\n", rc->X, rc->Y, rc->Width, rc->Height);
#endif		
		/* We do not call cairo_reset_clip because we want to take previous clipping into account */
		gdip_cairo_rectangle (graphics, rc->X, rc->Y, rc->Width, rc->Height, TRUE);
		cairo_clip (graphics->ct);
		SetClipping = TRUE;
	}

	/* Setup cairo */

	if (brush) {
		gdip_brush_setup (graphics, (GpBrush *)brush);
	} else {
		cairo_set_source_rgb (graphics->ct, 0., 0., 0.);
	}

	for (i=0; i<StringLen; i++) {
		if (StringDetails[i].Flags & STRING_DETAIL_LINESTART) {
			BYTE *String;
			int length = StringDetails[i].LineLen;
			int current_line_length = min (length + i, StringLen);

			/* To support the LineLimit flag */
			if ((StringDetails[i].Flags & STRING_DETAIL_HIDDEN)!=0){
#ifdef DRAWSTRING_DEBUG
				printf("Hidding partially visible line\n");
#endif
				i=StringLen;
				continue;
			}

			if (length > StringLen - i)
				length = StringLen - i;
			String = (BYTE*) ucs2_to_utf8 ((const gunichar2 *)(CleanString+i), length);
#ifdef DRAWSTRING_DEBUG
			printf("Displaying line >%s< (%d chars)\n", String, length);
#endif

			if ((fmt->formatFlags & StringFormatFlagsDirectionVertical)==0) {
				CursorX = rc->X + StringDetails[i].PosX;
				CursorY = rc->Y + StringDetails[i].PosY + LineHeight;

				gdip_cairo_move_to (graphics, CursorX, CursorY, FALSE, TRUE);
				cairo_show_text (graphics->ct, (const char *) String);
			} else {
				CursorY = rc->Y + StringDetails[i].PosX;
				CursorX = rc->X + StringDetails[i].PosY;

				/* Rotate text for vertical drawing */
				cairo_save (graphics->ct);
				gdip_cairo_move_to (graphics, CursorX, CursorY, FALSE, TRUE);
				cairo_rotate (graphics->ct, PI/2);
				cairo_show_text (graphics->ct, (const char *) String);
				cairo_restore (graphics->ct);
			}

#ifdef DRAWSTRING_DEBUG
			printf("Drawing %d chars at %d x %d (width=%f pixels)\n", StringDetails[i].LineLen, (int)CursorX, (int)CursorY, StringDetails[i+StringDetails[i].LineLen-1].PosX);
#endif
			GdipFree (String);

			if (font->style & (FontStyleUnderline | FontStyleStrikeout)) {
				double line_width = cairo_get_line_width (graphics->ct);

				/* Calculate the width of the line */
				cairo_set_line_width (graphics->ct, 1.0);
				j=StringDetails[i+StringDetails[i].LineLen-1].PosX+StringDetails[i+StringDetails[i].LineLen-1].Width;

				if (font->style & FontStyleStrikeout) {
					if ((fmt->formatFlags & StringFormatFlagsDirectionVertical)==0) {
						gdip_cairo_move_to (graphics, (int)(CursorX), (int)(CursorY-FontExtent.descent), FALSE, TRUE);
						gdip_cairo_line_to (graphics, (int)(CursorX+j), (int)(CursorY-FontExtent.descent), FALSE, TRUE);
					} else {
						gdip_cairo_move_to (graphics, (int)(CursorX+FontExtent.descent), (int)(CursorY), FALSE, TRUE);
						gdip_cairo_line_to (graphics, (int)(CursorX+FontExtent.descent), (int)(CursorY+j), FALSE, TRUE);
					}
				}

				if (font->style & FontStyleUnderline) {
					if ((fmt->formatFlags & StringFormatFlagsDirectionVertical)==0) {
						gdip_cairo_move_to (graphics, (int)(CursorX), (int)(CursorY+FontExtent.descent-2), FALSE, TRUE);
						gdip_cairo_line_to (graphics, (int)(CursorX+j), (int)(CursorY+FontExtent.descent-2), FALSE, TRUE);
					} else {
						gdip_cairo_move_to (graphics, (int)(CursorX+FontExtent.descent-2), (int)(CursorY), FALSE, TRUE);
						gdip_cairo_line_to (graphics, (int)(CursorX+FontExtent.descent-2), (int)(CursorY+j), FALSE, TRUE);
					}
				}

				cairo_stroke (graphics->ct);
				cairo_set_line_width (graphics->ct, line_width);
			}

			i+=StringDetails[i].LineLen-1;
		}
	}

	/* Handle Hotkey prefix */
	if (fmt->hotkeyPrefix==HotkeyPrefixShow && data->has_hotkeys) {
		GpStringDetailStruct *CurrentDetail = StringDetails;
		for (i=0; i<StringLen; i++) {
			if (CurrentDetail->Flags & STRING_DETAIL_HOTKEY) {
				if ((fmt->formatFlags & StringFormatFlagsDirectionVertical)==0) {
					CursorX = rc->X + StringDetails[i].PosX;
					CursorY = rc->Y + StringDetails[i].PosY + LineHeight;
				} else {
					CursorY = rc->Y + StringDetails[i].PosX;
					CursorX = rc->X + StringDetails[i].PosY;
				}

				if ((fmt->formatFlags & StringFormatFlagsDirectionVertical)==0) {
					cairo_set_line_width(graphics->ct, 1);
					gdip_cairo_move_to (graphics, (int)(CursorX), (int)(CursorY+FontExtent.descent), FALSE, TRUE);
					gdip_cairo_line_to (graphics, (int)(CursorX+CurrentDetail->Width), (int)(CursorY+FontExtent.descent), FALSE, TRUE);
					cairo_stroke (graphics->ct);
				} else {
					gdip_cairo_move_to (graphics, (int)(CursorX-FontExtent.descent), (int)(CursorY), FALSE, TRUE);
					gdip_cairo_line_to (graphics, (int)(CursorX-FontExtent.descent), (int)(CursorY+CurrentDetail->Width), FALSE, TRUE);
				}
			}
			CurrentDetail++;
		}
	}

	/* Restore the graphics clipping region */
	if (SetClipping)
		cairo_SetGraphicsClip (graphics);

	return Ok;
}
Esempio n. 3
0
GpStatus
gdip_pen_setup (GpGraphics *graphics, GpPen *pen)
{
	GpStatus status;
	cairo_matrix_t product;
	double widthx;

	if (!graphics || !pen)
		return InvalidParameter;

	status = gdip_brush_setup (graphics, pen->brush);
	if (status != Ok)
		return status;

	cairo_matrix_init_identity (&product);

	/* Here we use product of pen->matrix and graphics->copy_of_ctm.
	 * This gives us absolute results with respect to graphics. We
	 * do following irrespective of the pen->changed state since graphics
	 * has its own matrix and we need to multiply that with pen->matrix
	 * every time we perform stroke operations. Graphics matrix gets
	 * reset to its own state after stroking.
	 */
	cairo_matrix_multiply (&product, &pen->matrix, graphics->copy_of_ctm);
	/* Pen scaling by 0 are supported by MS GDI+ but would error in Cairo, see bug #338233 */
	if (gdip_near_zero (product.xx) || gdip_near_zero (product.yy)) {
		/* *both* X and Y are affected if either is 0 */
		product.xx = product.yy = 0.0001f;
	}
	cairo_set_matrix (graphics->ct, &product);

	/* Don't need to setup, if pen is the same as the cached pen and
	 * it is not changed. Just comparing pointers may not be sufficient
	 * to say that the pens are same. It is possible to have different
	 * pen on the same memory, but probability is very low. We would
	 * need a function to check the equality of the pens in that case.
	 */
	if (pen == graphics->last_pen && !pen->changed)
		return Ok;

	if (pen->width < 1.0) { /* we draw a pixel wide line if width is < 1.0 */
		double widthy = 1.0;
		widthx = 1.0;

		cairo_device_to_user_distance (graphics->ct, &widthx, &widthy);
	} else {
		widthx = (double) pen->width;
	}
	cairo_set_line_width (graphics->ct, widthx);

	cairo_set_miter_limit (graphics->ct, (double) pen->miter_limit);
	cairo_set_line_join (graphics->ct, convert_line_join (pen->line_join));
	cairo_set_line_cap (graphics->ct, convert_line_cap (pen));

	if (pen->dash_count > 0) {
		double *dash_array;

		/* note: pen->width may be different from what was used to
		call cairo_set_line_width, e.g. 0.0 (#78742) */
		dash_array = convert_dash_array (pen->dash_array, widthx, pen->dash_count);
		if (!dash_array)
			return OutOfMemory;

		cairo_set_dash (graphics->ct, dash_array, pen->dash_count, pen->dash_offset);
		GdipFree (dash_array);
	} else /* Clear the dashes, if set in previous calls */
		cairo_set_dash (graphics->ct, NULL, 0, 0);

	/* We are done with using all the changes in the pen. */
	pen->changed = FALSE;
	graphics->last_pen = pen;

	return gdip_get_status (cairo_status (graphics->ct));
}