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; }
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; }
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)); }