Sorry for the long delay.  I don't have write access to svn, so I'll 
need someone to commit it for me, or to get access to do so.

I'm still doing work in this area - right now I'm working with the 
issues for complex scripts in the TextBox and similar edit controls.

Thanks,
Jonathan

Sebastien Pouliot wrote:
> 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

Reply via email to