Hello Jonathan, On Thu, 2009-02-12 at 21:47 +0700, Jonathan Anderson wrote: > Sebastien Pouliot wrote: > >> There are a couple of issues that I've fixed since the patch I submitted > >> as well (fixed a problem with vertical text and another difference with > >> how MS GDI+ handles the NoWrap flag). Should I do another patch with > >> everything again, or just a patch on the patched version for those? > > > > You can issue a new, complete patch.
Sorry for the delay, I wanted to try it (out of curiosity) but did not have time yet. Anyway this should not block getting the source into SVN. Besides a few spaces/tabs issues (see inline) everything looks fine and since pango-support is not part of the default build please feel free* to commit your changes along with the ChangeLog. * as long as it does not touch the "main" source files and it follow the mono source conventions. Thanks! Sebastien > > Here's the new patch. Fixes from the previous one: > * vertical latin text is now drawn with characters in the correct direction > * NoWrap will still wrap on newline now (MS GDI+ does this) > > Jonathan Anderson > plain text document attachment (pangopatch2.diff) > Index: src/text-pango-private.h > =================================================================== > --- src/text-pango-private.h (revision 126715) > +++ src/text-pango-private.h (working copy) > @@ -36,17 +36,18 @@ > #include "graphics-private.h" > #include "stringformat-private.h" > > +#define PANGO_MAX (G_MAXINT / PANGO_SCALE) > +#define MAKE_SAFE_FOR_PANGO(x) ((x) > G_MAXINT/PANGO_SCALE ? > G_MAXINT/PANGO_SCALE : ((x) < G_MININT/PANGO_SCALE ? G_MININT/PANGO_SCALE : > (x))) > > #define GDIP_WINDOWS_ACCELERATOR '&' > -#define GDIP_PANGOHACK_ACCELERATOR ((char)1) > > #define text_DrawString pango_DrawString > #define text_MeasureString pango_MeasureString > #define text_MeasureCharacterRanges pango_MeasureCharacterRanges > > > -PangoLayout* gdip_pango_setup_layout (cairo_t *ct, GDIPCONST WCHAR > *stringUnicode, int length, GDIPCONST GpFont *font, > - GDIPCONST RectF *rc, RectF *box, GDIPCONST GpStringFormat *format); > +PangoLayout* gdip_pango_setup_layout (GpGraphics *graphics, GDIPCONST WCHAR > *stringUnicode, int length, GDIPCONST GpFont *font, > + GDIPCONST RectF *rc, RectF *box, GDIPCONST GpStringFormat *format, int > **charsRemoved); > > GpStatus pango_DrawString (GpGraphics *graphics, GDIPCONST WCHAR > *stringUnicode, int length, GDIPCONST GpFont *font, > GDIPCONST RectF *rc, GDIPCONST GpStringFormat *format, GpBrush *brush) > GDIP_INTERNAL; > Index: src/text-pango.c > =================================================================== > --- src/text-pango.c (revision 126715) > +++ src/text-pango.c (working copy) > @@ -46,45 +46,151 @@ > return list; > } > > -static void > -gdip_process_accelerators (gchar *text, int length, PangoAttrList *list) > +void > +gdip_set_array_values (int *array, int value, int num) > { > int i; > - for (i = 0; i < length; i++) { > - if (*(text + i) == GDIP_WINDOWS_ACCELERATOR) { > - /* don't show the prefix character */ > - *(text + i) = GDIP_PANGOHACK_ACCELERATOR; > - /* if the next character is an accelerator then skip > over it (&& == &) */ > - if ((i < length - 1) && (*(text + i + 1) == > GDIP_WINDOWS_ACCELERATOR)) { > - i++; > - } else if (list) { > - /* add an attribute on the next character */ > + for (i = 0; i < num; i++) > + array [i] = value; > +} > + > +static GString * > +gdip_process_string (gchar *text, int length, int removeAccelerators, int > trimSpace, PangoAttrList *list, int **charsRemoved) > +{ > + int i, j; > + int nonws = 0; > + gchar *iter; > + gchar *iter2; > + gunichar ch; > + GString *res = g_string_sized_new (length); ^ space/tab issue > + > + /* fast version: just check for final newline and remove */ > + if (!removeAccelerators && !trimSpace) { > + j = length; > + if (j > 0 && text [j-1] == '\n') { > + j--; > + if (j > 0 && text [j-1] == '\r') > + j--; > + } > + g_string_append_len (res, text, j); > + if (j == 0 && length > 0) { > + g_string_append_c (res, ' '); > + j++; > + } > + if (charsRemoved && *charsRemoved) { > + int prevj = (g_utf8_prev_char (res->str + j) - > res->str); > + gdip_set_array_values (*charsRemoved + prevj, length - > j, j - prevj); > + } > + return res; > + } > + > + iter = text; > + i = 0; > + j = 0; > + while (iter - text < length) { > + ch = g_utf8_get_char (iter); > + if (ch == GDIP_WINDOWS_ACCELERATOR && removeAccelerators && > (iter - text < length - 1)) { > + nonws = 1; > + iter2 = g_utf8_next_char (iter); > + i += iter2 - iter; > + iter = iter2; > + ch = g_utf8_get_char (iter); > + /* add an attribute on the next character */ > + if (list && (iter - text < length) && (ch != > GDIP_WINDOWS_ACCELERATOR)) { > PangoAttribute *attr = pango_attr_underline_new > (PANGO_UNDERLINE_LOW); > - attr->start_index = i + 1; > - attr->end_index = i + 2; > + attr->start_index = j; > + attr->end_index = j + g_utf8_next_char (iter) - > iter; > pango_attr_list_insert (list, attr); > } > + } else if (!g_unichar_isspace (ch)) { > + nonws = 1; > + } else if (trimSpace && ch != '\r' && ch != '\n') { > + /* unless specified we don't consider the trailing > spaces, unless there is just one space (#80680) */ > + for (iter2 = g_utf8_next_char (iter); iter2 - text < > length; iter2 = g_utf8_next_char (iter2)) { > + ch = g_utf8_get_char (iter2); > + if (ch == '\r' || ch == '\n') > + break; > + if (!g_unichar_isspace (ch)) { > + g_string_append_len (res, iter, iter2 - > iter); > + if (charsRemoved && *charsRemoved) > + gdip_set_array_values > ((*charsRemoved)+j, i - j, iter2 - iter); > + j += iter2 - iter; > + break; > + } > + } > + i += iter2 - iter; > + iter = iter2; > + continue; > + } else if ((ch == '\r' && (iter - text == length - 2) && > (*g_utf8_next_char (iter) == '\n')) || (ch == '\n' && iter - text == length - > 1)) { > + /* in any case, ignore a final newline as pango will > add an extra line to the measurement while gdi+ does not */ > + i = length; > + break; > } > + iter2 = g_utf8_next_char (iter); > + g_string_append_len (res, iter, iter2 - iter); > + /* save these for string lengths later */ > + if (charsRemoved && *charsRemoved) > + gdip_set_array_values ((*charsRemoved)+j, i - j, iter2 > - iter); > + j += iter2 - iter; > + i += iter2 - iter; > + iter = iter2; > } > + /* always ensure that at least one space is measured */ > + if (!nonws && trimSpace) { > + g_string_append_c (res, ' '); > + j++; > + } > + if (charsRemoved && *charsRemoved && j > 0) { > + int prevj = (g_utf8_prev_char (res->str + j) - res->str); > + gdip_set_array_values (*charsRemoved + prevj, i - j, j - prevj); > + } > + return res; > } > > PangoLayout* > -gdip_pango_setup_layout (cairo_t *ct, GDIPCONST WCHAR *stringUnicode, int > length, GDIPCONST GpFont *font, > - GDIPCONST RectF *rc, RectF *box, GDIPCONST GpStringFormat *format) > +gdip_pango_setup_layout (GpGraphics *graphics, GDIPCONST WCHAR > *stringUnicode, int length, GDIPCONST GpFont *font, > + GDIPCONST RectF *rc, RectF *box, GDIPCONST GpStringFormat *format, int > **charsRemoved) > { > GpStringFormat *fmt; > PangoLayout *layout; > PangoContext *context; > - PangoMatrix matrix = PANGO_MATRIX_INIT; > - PangoRectangle logical; > + PangoRectangle logical; /* logical size of text (used for alignment) > */ > + PangoRectangle ink; /* ink size of text (to pixel boundaries) */ > PangoAttrList *list = NULL; > + GString *ftext; ^ space/tab issue > + PangoTabArray *tabs; > + PangoLayoutIter *iter; > + int i; > + int FrameWidth; /* rc->Width (or rc->Height if vertical) */ > + int FrameHeight; /* rc->Height (or rc->Width if vertical) */ > + int FrameX; /* rc->X (or rc->Y if vertical) */ > + int FrameY; /* rc->Y (or rc->X if vertical) */ > + int y0; /* y0,y1,clipNN used for checking line positions > vs. clip rectangle */ > + int y1; > + double clipx1; > + double clipx2; > + double clipy1; > + double clipy2; > + int trimSpace; /* whether or not to trim the space */ > > gchar *text = ucs2_to_utf8 (stringUnicode, length); > if (!text) > return NULL; > + length = strlen (text); ^ space/tab issue > -//g_warning ("layout >%s< (%d) [x %g, y %g, w %g, h %g] [font %s, %g > points]", text, length, rc->X, rc->Y, rc->Width, rc->Height, font->face, > font->emSize); > + if (charsRemoved) { > + (*charsRemoved) = GdipAlloc (sizeof (int) * length); > + if (!*charsRemoved) { > + GdipFree (text); > + return NULL; > + } > + memset (*charsRemoved, 0, sizeof (int) * length); > + } > > + /* TODO - Digit substitution */ > + > +// g_warning ("layout >%s< (%d) [x %g, y %g, w %g, h %g] [font %s, %g > points]", text, length, rc->X, rc->Y, rc->Width, FrameHeight, font->face, > font->emSize); > + > /* a NULL format is valid, it means get the generic default values (and > free them later) */ > if (!format) { > GpStatus status = GdipStringFormatGetGenericDefault > ((GpStringFormat **)&fmt); > @@ -96,36 +202,46 @@ > fmt = (GpStringFormat *)format; > } > > - /* unless specified we don't consider the trailing spaces, unless there > is just one space (#80680) */ > - if ((fmt->formatFlags & StringFormatFlagsMeasureTrailingSpaces) == 0) { > - while ((length > 0) && (isspace (*(text + length - 1)))) > - length--; > - if (length == 0) > - length = 1; > - } > + layout = pango_cairo_create_layout (graphics->ct); > > - layout = pango_cairo_create_layout (ct); > - > /* context is owned by Pango (i.e. not referenced counted) do not free > */ > context = pango_layout_get_context (layout); > > pango_layout_set_font_description (layout, > gdip_get_pango_font_description ((GpFont*) font)); > > - if ((rc->Width <= 0.0) || (fmt->formatFlags & StringFormatFlagsNoWrap)) > { > + if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { > + FrameWidth = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 > (rc->Height)); > + FrameHeight = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 > (rc->Width)); > + FrameX = SAFE_FLOAT_TO_UINT32 (rc->Y); > + FrameY = SAFE_FLOAT_TO_UINT32 (rc->X); > + } else { > + FrameWidth = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 > (rc->Width)); > + FrameHeight = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 > (rc->Height)); > + FrameX = SAFE_FLOAT_TO_UINT32 (rc->X); > + FrameY = SAFE_FLOAT_TO_UINT32 (rc->Y); > + } > + //g_warning("FW: %d\tFH: %d", FrameWidth, FrameHeight); > + > + if ((FrameWidth <= 0) || (fmt->formatFlags & StringFormatFlagsNoWrap)) { > pango_layout_set_width (layout, -1); > + //g_warning ("Setting width: %d", -1); > } else { > - /* minus one to deal with our AA offset */ > - int width = rc->Width - 1; > - /* TODO incomplete (missing height adjustment) */ > - if ((fmt->formatFlags & StringFormatFlagsNoFitBlackBox) == 0) > - width -= 2; > - pango_layout_set_width (layout, width * PANGO_SCALE); > + pango_layout_set_width (layout, FrameWidth * PANGO_SCALE); > + //g_warning ("Setting width: %d", FrameWidth * PANGO_SCALE); > } > + > + if ((rc->Width != 0) && (rc->Height != 0) && ((fmt->formatFlags & > StringFormatFlagsNoClip) == 0)) { > +// g_warning ("\tclip [%g %g %g %g]", rc->X, rc->Y, rc->Width, rc->Height); > + /* We do not call cairo_reset_clip because we want to take > previous clipping into account */ > + /* Use rc instead of frame variables because this is > pre-transform */ > + gdip_cairo_rectangle (graphics, rc->X, rc->Y, rc->Width, > rc->Height, TRUE); > + cairo_clip (graphics->ct); > + } > > - if (fmt->formatFlags & StringFormatFlagsDirectionRightToLeft) { > - /* with GDI+ the API not the renderer makes the direction > decision */ > - pango_layout_set_auto_dir (layout, FALSE); > - pango_context_set_base_dir (context, PANGO_DIRECTION_RTL); > + /* with GDI+ the API not the renderer makes the direction decision */ > + pango_layout_set_auto_dir (layout, FALSE); > + if (!(fmt->formatFlags & StringFormatFlagsDirectionRightToLeft) != > !(fmt->formatFlags & StringFormatFlagsDirectionVertical)) { > + pango_context_set_base_dir (context, PANGO_DIRECTION_WEAK_RTL); > pango_layout_context_changed (layout); > > /* horizontal alignment */ > @@ -141,6 +257,8 @@ > break; > } > } else { > + /* pango default base dir is WEAK_LTR, which is what we want */ > + > /* horizontal alignment */ > switch (fmt->alignment) { > case StringAlignmentNear: > @@ -158,9 +276,18 @@ > #ifdef PANGO_VERSION_CHECK > #if PANGO_VERSION_CHECK(1,16,0) > if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { > + if (fmt->formatFlags & StringFormatFlagsDirectionRightToLeft) { > + cairo_rotate (graphics->ct, M_PI/2.0); > + cairo_translate (graphics->ct, 0, -FrameHeight); > + pango_cairo_update_context (graphics->ct, context); > + } else { > + cairo_rotate (graphics->ct, 3.0*M_PI/2.0); > + cairo_translate (graphics->ct, -FrameWidth, 0); > + pango_cairo_update_context (graphics->ct, context); > + } > /* only since Pango 1.16 */ > - pango_context_set_base_gravity (context, PANGO_GRAVITY_EAST); > - pango_context_set_gravity_hint (context, > PANGO_GRAVITY_HINT_STRONG); > + pango_context_set_base_gravity (context, PANGO_GRAVITY_AUTO); > + pango_context_set_gravity_hint (context, > PANGO_GRAVITY_HINT_LINE); > pango_layout_context_changed (layout); > } > #endif > @@ -169,38 +296,27 @@ > /* TODO - StringFormatFlagsDisplayFormatControl > scan and replace them ??? */ > > - /* TODO - StringFormatFlagsLineLimit */ > - > - if ((rc->Width != 0) && (rc->Height != 0) && ((fmt->formatFlags & > StringFormatFlagsNoClip) == 0)) { > -//g_warning ("\tclip [%g %g %g %g]", rc->X, rc->Y, rc->Width, rc->Height); > - /* We do not call cairo_reset_clip because we want to take > previous clipping into account */ > - cairo_rectangle (ct, rc->X, rc->Y, rc->Width + 0.5, rc->Height > + 0.5); > - cairo_clip (ct); > - } > - > + /* Trimming options seem to apply only to the end of the string - gdi+ > will still wrap > + * with preference to word first, then character. Unfortunately, pango > doesn't have > + * any way to differentiate wrapping behavior from trimming behavior > that I could find */ > + pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR); > switch (fmt->trimming) { > case StringTrimmingNone: > - pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR); > pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE); > break; > case StringTrimmingCharacter: > - pango_layout_set_wrap (layout, PANGO_WRAP_CHAR); > pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE); > break; > case StringTrimmingWord: > - pango_layout_set_wrap (layout, PANGO_WRAP_WORD); > pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE); > break; > case StringTrimmingEllipsisCharacter: > - pango_layout_set_wrap (layout, PANGO_WRAP_CHAR); > pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); > break; > case StringTrimmingEllipsisWord: > - pango_layout_set_wrap (layout, PANGO_WRAP_WORD); > pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); > break; > case StringTrimmingEllipsisPath: > - pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR); > pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_MIDDLE); > break; > } > @@ -233,59 +349,138 @@ > } > } > > + if (fmt->numtabStops > 0) { > + float tabPosition; > + tabs = pango_tab_array_new (fmt->numtabStops, TRUE); > + tabPosition = fmt->firstTabOffset; > + for (i = 0; i < fmt->numtabStops; i++) { > + tabPosition += fmt->tabStops[i]; > + pango_tab_array_set_tab (tabs, i, PANGO_TAB_LEFT, > (gint)min (tabPosition, PANGO_MAX) * PANGO_SCALE); > + } > + pango_layout_set_tabs (layout, tabs); > + pango_tab_array_free (tabs); > + } > + > + //g_warning ("length before ws removal: %d", length); > + trimSpace = (fmt->formatFlags & StringFormatFlagsMeasureTrailingSpaces) > == 0; > switch (fmt->hotkeyPrefix) { > case HotkeyPrefixHide: > /* we need to remove any accelerator from the string */ > - gdip_process_accelerators (text, length, NULL); > + ftext = gdip_process_string (text, length, 1, trimSpace, NULL, > charsRemoved); > break; > case HotkeyPrefixShow: > /* optimization: is seems that we never see the hotkey when > using an underline font */ > if (font->style & FontStyleUnderline) { > /* so don't bother drawing it (and simply add the '&' > character) */ > - gdip_process_accelerators (text, length, NULL); > + ftext = gdip_process_string (text, length, 1, > trimSpace, NULL, charsRemoved); > } else { > /* find accelerator and add attribute to the next > character (unless it's the prefix too) */ > if (!list) > list = gdip_get_layout_attributes (layout); > - gdip_process_accelerators (text, length, list); > + ftext = gdip_process_string (text, length, 1, > trimSpace, list, charsRemoved); > } > break; > default: > + ftext = gdip_process_string (text, length, 0, trimSpace, NULL, > charsRemoved); > break; > } > + length = ftext->len; > + //g_warning ("length after ws removal: %d", length); > > if (list) { > pango_layout_set_attributes (layout, list); > pango_attr_list_unref (list); > } > > - pango_layout_set_text (layout, text, length); > +// g_warning("\tftext>%s< (%d)", ftext->str, -1); > + pango_layout_set_text (layout, ftext->str, ftext->len); > GdipFree (text); > + g_string_free (ftext, TRUE); ^ tab/space > > - pango_layout_get_pixel_extents (layout, NULL, &logical); > -//g_warning ("\tlogical\t[x %d, y %d, w %d, h %d]", logical.x, logical.y, > logical.width, logical.height); > + /* Trim the text after the last line for ease of counting > lines/characters */ > + /* Also prevents drawing whole lines outside the boundaries if NoClip > was specified */ > + /* In case of pre-existing clipping, use smaller of clip rectangle or > our specified height */ > + if (FrameHeight > 0) { > + cairo_clip_extents (graphics->ct, &clipx1, &clipy1, &clipx2, > &clipy2); > + if (clipy2 > 0) > + clipy2 = min (clipy2, FrameHeight + FrameY); > + else > + clipy2 = FrameHeight + FrameY; > + iter = pango_layout_get_iter (layout); > + do { > + if (iter == NULL) > + break; > + pango_layout_iter_get_line_yrange (iter, &y0, &y1); > + //g_warning("yrange: %d %d clipy2: %f", y0 / > PANGO_SCALE, y1 / PANGO_SCALE, clipy2); > + /* StringFormatFlagsLineLimit */ > + if (((fmt->formatFlags & StringFormatFlagsLineLimit) && > y1 / PANGO_SCALE > clipy2) || (y0 / PANGO_SCALE > clipy2)) { > + PangoLayoutLine *line = > pango_layout_iter_get_line_readonly (iter); > + pango_layout_set_text (layout, > pango_layout_get_text (layout), line->start_index); > + break; > + } > + } while (pango_layout_iter_next_line (iter)); > + pango_layout_iter_free (iter); > + } > > - box->X = rc->X; > - box->Y = rc->Y; > - box->Height = logical.height; > - /* add an extra pixel for our AA hack + 2 more if we don't draw on the > box itself */ > - box->Width = logical.width + (fmt->formatFlags & > StringFormatFlagsNoFitBlackBox) ? 1 : 3; > -//g_warning ("\tbox\t[x %g, y %g, w %g, h %g]", box->X, box->Y, box->Width, > box->Height); > + pango_layout_get_pixel_extents (layout, &ink, &logical); > + //g_warning ("\tlogical\t[x %d, y %d, w %d, h %d][x %d, y %d, w %d, h %d]", > logical.x, logical.y, logical.width, logical.height, ink.x, ink.y, ink.width, > ink.height); > > + if ((fmt->formatFlags & StringFormatFlagsNoFitBlackBox) == 0) { > + /* By default don't allow overhang - ink space may be larger > than logical space */ > + if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { > + box->X = min (ink.y, logical.y); > + box->Y = min (ink.x, logical.x); > + box->Height = max (ink.width, logical.width); > + box->Width = max (ink.height, logical.height); > + } else { > + box->X = min (ink.x, logical.x); > + box->Y = min (ink.y, logical.y); > + box->Height = max (ink.height, logical.height); > + box->Width = max (ink.width, logical.width); > + } > + } else { > + /* Allow overhang */ > + if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { > + box->X = logical.y; > + box->Y = logical.x; > + box->Height = logical.width; > + box->Width = logical.height; > + } else { > + box->X = logical.x; > + box->Y = logical.y; > + box->Height = logical.height; > + box->Width = logical.width; > + } > + } > + //g_warning ("\tbox\t[x %g, y %g, w %g, h %g]", box->X, box->Y, box->Width, > box->Height); > + > /* vertical alignment*/ > - switch (fmt->lineAlignment) { > - case StringAlignmentNear: > - break; > - case StringAlignmentCenter: > - box->Y += (rc->Height - logical.height) / 2; > - break; > - case StringAlignmentFar: > - box->Y += (rc->Height - logical.height); > - break; > + if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { > + switch (fmt->lineAlignment) { > + case StringAlignmentNear: > + break; > + case StringAlignmentCenter: > + box->X += (rc->Width - box->Width) / 2; > + break; > + case StringAlignmentFar: > + box->X += (rc->Width - box->Width); > + break; > + } > + } else { > + switch (fmt->lineAlignment) { > + case StringAlignmentNear: > + break; > + case StringAlignmentCenter: > + box->Y += (rc->Height - box->Height) / 2; > + break; > + case StringAlignmentFar: > + box->Y += (rc->Height - box->Height); > + break; > + } > } > -//g_warning ("va-box\t[x %g, y %g, w %g, h %g]", box->X, box->Y, box->Width, > box->Height); > +// g_warning ("va-box\t[x %g, y %g, w %g, h %g]", box->X, box->Y, > box->Width, box->Height); > > - pango_cairo_update_layout (ct, layout); > + pango_cairo_update_layout (graphics->ct, layout); > > return layout; > } > @@ -297,22 +492,22 @@ > 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->ct, stringUnicode, length, > font, rc, &box, format); > + layout = gdip_pango_setup_layout (graphics, stringUnicode, length, > font, rc, &box, format, NULL); > if (!layout) { > cairo_restore (graphics->ct); > return OutOfMemory; > } > > - /* Setup cairo */ > - if (brush) { > - gdip_brush_setup (graphics, brush); > - } else { > - cairo_set_source_rgb (graphics->ct, 0., 0., 0.); > - } > - > - gdip_cairo_move_to (graphics, box.X, box.Y, FALSE, TRUE); > + gdip_cairo_move_to (graphics, rc->X, rc->Y, FALSE, TRUE); > pango_cairo_show_layout (graphics->ct, layout); > > g_object_unref (layout); > @@ -325,25 +520,96 @@ > GDIPCONST GpStringFormat *format, RectF *boundingBox, int > *codepointsFitted, int *linesFilled) > { > PangoLayout *layout; > + PangoLayoutLine *line; > + PangoRectangle logical; > + PangoLayoutIter *iter; > + int *charsRemoved = NULL; > > cairo_save (graphics->ct); > > - layout = gdip_pango_setup_layout (graphics->ct, stringUnicode, length, > font, rc, boundingBox, format); > + layout = gdip_pango_setup_layout (graphics, stringUnicode, length, > font, rc, boundingBox, format, &charsRemoved); > if (!layout) { > cairo_restore (graphics->ct); > return OutOfMemory; > } > > if (codepointsFitted) { > - // TODO - dummy (total) value returned > - *codepointsFitted = length; > + int charsFitted; > + int lastIndex; > + int y0; > + int y1; > + double min_x; > + double max_x; > + double max_y; > + const char *layoutText; > + if (boundingBox && format && (format->formatFlags & > StringFormatFlagsDirectionVertical)) { > + min_x = boundingBox->Y; > + max_x = boundingBox->Y + boundingBox->Height; > + max_y = boundingBox->X + boundingBox->Width; > + } else if (boundingBox) { > + min_x = boundingBox->X; > + max_x = boundingBox->X + boundingBox->Width; > + max_y = boundingBox->Y + boundingBox->Height; > + } else if (format && (format->formatFlags & > StringFormatFlagsDirectionVertical)) { > + min_x = rc->Y; > + max_x = rc->Y + rc->Height; > + max_y = rc->X + rc->Width; > + } else { > + min_x = rc->X; > + max_x = rc->X + rc->Width; > + max_y = rc->Y + rc->Height; > + } > + lastIndex = 0; > + iter = pango_layout_get_iter (layout); > + do { > + if (iter == NULL) > + break; > + pango_layout_iter_get_line_yrange (iter, &y0, &y1); > + if (y0 / PANGO_SCALE >= max_y) > + break; > + if (pango_layout_iter_at_last_line (iter)) { > + do { > + pango_layout_iter_get_char_extents > (iter, &logical); > + /* check both max and min to catch > right-to-left text, also width may be negative */ > + if ((logical.x / PANGO_SCALE > max_x || > (logical.x + logical.width) / PANGO_SCALE > max_x) || (logical.x / > PANGO_SCALE < min_x || (logical.x + logical.width) / PANGO_SCALE < min_x)) > + break; > + lastIndex = pango_layout_iter_get_index > (iter); > + } while (pango_layout_iter_next_char (iter)); > + break; > + } else { > + line = pango_layout_iter_get_line_readonly > (iter); > + lastIndex = line->start_index + line->length - > 1; > + } > + } while (pango_layout_iter_next_line (iter)); > + pango_layout_iter_free (iter); > + layoutText = pango_layout_get_text (layout); > + /* this can happen when the string ends in a newline */ > + if (lastIndex >= strlen (layoutText)) > + lastIndex = strlen (layoutText) - 1; > + /* Add back in any & characters removed and the final newline > characters (if any) */ > + charsFitted = g_utf8_strlen (layoutText, lastIndex + 1) + > charsRemoved [lastIndex]; > + //g_warning("lastIndex: %d\t\tcharsRemoved: %d", lastIndex, > charsRemoved[lastIndex]); > + /* safe because of null termination */ > + switch (layoutText [lastIndex + 1]) { > + case '\r': > + charsFitted++; > + if (layoutText [lastIndex + 2] == '\n') > + charsFitted++; > + break; > + case '\n': > + charsFitted++; > + break; > + } > + *codepointsFitted = charsFitted; > } > > + GdipFree (charsRemoved); > + > if (linesFilled) { > *linesFilled = pango_layout_get_line_count (layout); > -//g_warning ("linesFilled %d", *linesFilled); > +// g_warning ("linesFilled %d", *linesFilled); > } > -//else g_warning ("linesFilled %d", pango_layout_get_line_count (layout)); > +// else g_warning ("linesFilled %d", pango_layout_get_line_count (layout)); > > g_object_unref (layout); > cairo_restore (graphics->ct); > @@ -361,7 +627,7 @@ > > cairo_save (graphics->ct); > > - layout = gdip_pango_setup_layout (graphics->ct, stringUnicode, length, > font, layoutRect, &boundingBox, format); > + layout = gdip_pango_setup_layout (graphics, stringUnicode, length, > font, layoutRect, &boundingBox, format, NULL); > if (!layout) { > cairo_restore (graphics->ct); > return OutOfMemory; > @@ -402,7 +668,16 @@ > charRect.Y = (float)box.y / PANGO_SCALE; > charRect.Width = (float)box.width / PANGO_SCALE; > charRect.Height = (float)box.height / PANGO_SCALE; > -//g_warning ("[%d] [%d : %d-%d] %c [x %g y %g w %g h %g]", i, j, start, end, > (char)stringUnicode[j], charRect.X, charRect.Y, charRect.Width, > charRect.Height); > + /* Normalize values (width/height can be negative) */ > + if (charRect.Width < 0) { > + charRect.Width = -charRect.Width; > + charRect.X -= charRect.Width; > + } > + if (charRect.Height < 0) { > + charRect.Height = -charRect.Height; > + charRect.Y -= charRect.Height; > + } > +// g_warning ("[%d] [%d : %d-%d] %c [x %g y %g w %g h %g]", i, j, start, > end, (char)stringUnicode[j], charRect.X, charRect.Y, charRect.Width, > charRect.Height); > status = GdipCombineRegionRect (regions [i], &charRect, > CombineModeUnion); > if (status != Ok) > break; > Index: src/graphics-path.c > =================================================================== > --- src/graphics-path.c (revision 126715) > +++ src/graphics-path.c (working copy) > @@ -1212,7 +1212,7 @@ > PangoLayout* layout; > > cairo_save (cr); > - layout = gdip_pango_setup_layout (cr, string, length, font, layoutRect, > &box, format); > + layout = gdip_pango_setup_layout (cr, string, length, font, layoutRect, > &box, format, NULL); > pango_cairo_layout_path (cr, layout); > g_object_unref (layout); > cairo_restore (cr); _______________________________________________ Mono-winforms-list maillist - Mono-winforms-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-winforms-list