Vincent Povirk : gdiplus: Rewrite GdipMeasureString using a helper function .

Alexandre Julliard julliard at winehq.org
Wed Mar 31 10:04:50 CDT 2010


Module: wine
Branch: master
Commit: 3cee74c61d1e4065259739721eb50083c5a47960
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=3cee74c61d1e4065259739721eb50083c5a47960

Author: Vincent Povirk <vincent at codeweavers.com>
Date:   Tue Mar 30 13:41:04 2010 -0500

gdiplus: Rewrite GdipMeasureString using a helper function.

---

 dlls/gdiplus/graphics.c |  178 ++++++++++++++++++++++++++++++++++------------
 1 files changed, 131 insertions(+), 47 deletions(-)

diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 722d7f4..afbe571 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -3550,61 +3550,37 @@ GpStatus WINGDIPAPI GdipIsVisibleRectI(GpGraphics *graphics, INT x, INT y, INT w
     return GdipIsVisibleRect(graphics, (REAL)x, (REAL)y, (REAL)width, (REAL)height, result);
 }
 
-GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics* graphics,
-        GDIPCONST WCHAR* string, INT length, GDIPCONST GpFont* font,
-        GDIPCONST RectF* layoutRect, GDIPCONST GpStringFormat *stringFormat,
-        INT regionCount, GpRegion** regions)
-{
-    FIXME("stub: %p %s %d %p %p %p %d %p\n", graphics, debugstr_w(string),
-            length, font, layoutRect, stringFormat, regionCount, regions);
+typedef GpStatus (*gdip_format_string_callback)(GpGraphics *graphics,
+    GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
+    GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
+    INT lineno, const RectF *bounds, void *user_data);
 
-    if (!(graphics && string && font && layoutRect && stringFormat && regions))
-        return InvalidParameter;
-
-    return NotImplemented;
-}
-
-/* Find the smallest rectangle that bounds the text when it is printed in rect
- * according to the format options listed in format. If rect has 0 width and
- * height, then just find the smallest rectangle that bounds the text when it's
- * printed at location (rect->X, rect-Y). */
-GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics,
+static GpStatus gdip_format_string(GpGraphics *graphics,
     GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font,
-    GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, RectF *bounds,
-    INT *codepointsfitted, INT *linesfilled)
+    GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
+    gdip_format_string_callback callback, void *user_data)
 {
-    HFONT oldfont;
     WCHAR* stringdup;
-    INT sum = 0, height = 0, fit, fitcpy, max_width = 0, i, j, lret, nwidth,
-        nheight, lineend;
+    INT sum = 0, height = 0, fit, fitcpy, i, j, lret, nwidth,
+        nheight, lineend, lineno = 0;
+    RectF bounds;
+    StringAlignment halign;
+    GpStatus stat = Ok;
     SIZE size;
 
-    TRACE("(%p, %s, %i, %p, %s, %p, %p, %p, %p)\n", graphics,
-        debugstr_wn(string, length), length, font, debugstr_rectf(rect), format,
-        bounds, codepointsfitted, linesfilled);
-
-    if(!graphics || !string || !font || !rect || !bounds)
-        return InvalidParameter;
-
-    if(linesfilled) *linesfilled = 0;
-    if(codepointsfitted) *codepointsfitted = 0;
-
-    if(format)
-        TRACE("may be ignoring some format flags: attr %x\n", format->attr);
-
     if(length == -1) length = lstrlenW(string);
 
     stringdup = GdipAlloc((length + 1) * sizeof(WCHAR));
     if(!stringdup) return OutOfMemory;
 
-    oldfont = SelectObject(graphics->hdc, CreateFontIndirectW(&font->lfw));
     nwidth = roundr(rect->Width);
     nheight = roundr(rect->Height);
 
-    if((nwidth == 0) && (nheight == 0))
-        nwidth = nheight = INT_MAX;
+    if (nwidth == 0) nwidth = INT_MAX;
+    if (nheight == 0) nheight = INT_MAX;
 
     for(i = 0, j = 0; i < length; i++){
+        /* FIXME: This makes the indexes passed to callback inaccurate. */
         if(!isprintW(string[i]) && (string[i] != '\n'))
             continue;
 
@@ -3612,9 +3588,11 @@ GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics,
         j++;
     }
 
-    stringdup[j] = 0;
     length = j;
 
+    if (format) halign = format->align;
+    else halign = StringAlignmentNear;
+
     while(sum < length){
         GetTextExtentExPointW(graphics->hdc, stringdup + sum, length - sum,
                               nwidth, &fit, NULL, &size);
@@ -3657,12 +3635,38 @@ GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics,
         GetTextExtentExPointW(graphics->hdc, stringdup + sum, lineend,
                               nwidth, &j, NULL, &size);
 
-        sum += fit + (lret < fitcpy ? 1 : 0);
-        if(codepointsfitted) *codepointsfitted = sum;
+        bounds.Width = size.cx;
+
+        if(height + size.cy > nheight)
+            bounds.Height = nheight - (height + size.cy);
+        else
+            bounds.Height = size.cy;
+
+        bounds.Y = rect->Y + height;
 
+        switch (halign)
+        {
+        case StringAlignmentNear:
+        default:
+            bounds.X = rect->X;
+            break;
+        case StringAlignmentCenter:
+            bounds.X = rect->X + (rect->Width/2) - (bounds.Width/2);
+            break;
+        case StringAlignmentFar:
+            bounds.X = rect->X + rect->Width - bounds.Width;
+            break;
+        }
+
+        stat = callback(graphics, stringdup, sum, lineend,
+            font, rect, format, lineno, &bounds, user_data);
+
+        if (stat != Ok)
+            break;
+
+        sum += fit + (lret < fitcpy ? 1 : 0);
         height += size.cy;
-        if(linesfilled) *linesfilled += size.cy;
-        max_width = max(max_width, size.cx);
+        lineno++;
 
         if(height > nheight)
             break;
@@ -3672,12 +3676,92 @@ GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics,
             break;
     }
 
+    GdipFree(stringdup);
+
+    return stat;
+}
+
+GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics* graphics,
+        GDIPCONST WCHAR* string, INT length, GDIPCONST GpFont* font,
+        GDIPCONST RectF* layoutRect, GDIPCONST GpStringFormat *stringFormat,
+        INT regionCount, GpRegion** regions)
+{
+    FIXME("stub: %p %s %d %p %p %p %d %p\n", graphics, debugstr_w(string),
+            length, font, layoutRect, stringFormat, regionCount, regions);
+
+    if (!(graphics && string && font && layoutRect && stringFormat && regions))
+        return InvalidParameter;
+
+    return NotImplemented;
+}
+
+struct measure_string_args {
+    RectF *bounds;
+    INT *codepointsfitted;
+    INT *linesfilled;
+};
+
+static GpStatus measure_string_callback(GpGraphics *graphics,
+    GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
+    GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
+    INT lineno, const RectF *bounds, void *user_data)
+{
+    struct measure_string_args *args = user_data;
+
+    if (bounds->Width > args->bounds->Width)
+        args->bounds->Width = bounds->Width;
+
+    if (bounds->Height + bounds->Y > args->bounds->Height + args->bounds->Y)
+        args->bounds->Height = bounds->Height + bounds->Y - args->bounds->Y;
+
+    if (args->codepointsfitted)
+        *args->codepointsfitted = index + length;
+
+    if (args->linesfilled)
+        *args->linesfilled += bounds->Height;
+
+    return Ok;
+}
+
+/* Find the smallest rectangle that bounds the text when it is printed in rect
+ * according to the format options listed in format. If rect has 0 width and
+ * height, then just find the smallest rectangle that bounds the text when it's
+ * printed at location (rect->X, rect-Y). */
+GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics,
+    GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font,
+    GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, RectF *bounds,
+    INT *codepointsfitted, INT *linesfilled)
+{
+    HFONT oldfont;
+    struct measure_string_args args;
+
+    TRACE("(%p, %s, %i, %p, %s, %p, %p, %p, %p)\n", graphics,
+        debugstr_wn(string, length), length, font, debugstr_rectf(rect), format,
+        bounds, codepointsfitted, linesfilled);
+
+    if(!graphics || !string || !font || !rect || !bounds)
+        return InvalidParameter;
+
+    if(linesfilled) *linesfilled = 0;
+    if(codepointsfitted) *codepointsfitted = 0;
+
+    if(format)
+        TRACE("may be ignoring some format flags: attr %x\n", format->attr);
+
+    oldfont = SelectObject(graphics->hdc, CreateFontIndirectW(&font->lfw));
+
     bounds->X = rect->X;
     bounds->Y = rect->Y;
-    bounds->Width = (REAL)max_width;
-    bounds->Height = (REAL) min(height, nheight);
+    bounds->Width = 0.0;
+    bounds->Height = 0.0;
+
+    args.bounds = bounds;
+    args.codepointsfitted = codepointsfitted;
+    args.linesfilled = linesfilled;
+
+    gdip_format_string(graphics, string, length, font, rect, format,
+        measure_string_callback, &args);
 
-    GdipFree(stringdup);
     DeleteObject(SelectObject(graphics->hdc, oldfont));
 
     return Ok;




More information about the wine-cvs mailing list