Show
Ignore:
Timestamp:
05/17/08 11:34:28 (8 months ago)
Author:
Frank Benoit <benoit@tionex.de>
branch:
default
Message:

Update to SWT 3.4M7

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • dwt/graphics/TextLayout.d

    </
    r212 r213  
    1717import dwt.internal.Compatibility; 
    1818import dwt.internal.gdip.Gdip; 
     19 
    1920import dwt.internal.win32.OS; 
    2021 
     
    5253 */ 
    5354public final class TextLayout : Resource { 
     55    alias Resource.init_ init_; 
     56 
    5457    Font font; 
    5558    String text, segmentsText; 
     
    6467    int[] segments; 
    6568    StyleItem[] styles; 
     69    int stylesCount; 
    6670 
    6771    StyleItem[] allRuns; 
     
    9094    } 
    9195 
     96    /* IME has a copy of these constants */ 
     97    static const int UNDERLINE_IME_DOT = 1 << 16; 
     98    static const int UNDERLINE_IME_DASH = 2 << 16; 
     99    static const int UNDERLINE_IME_THICK = 3 << 16; 
     100 
    92101    class StyleItem { 
    93102        TextStyle style; 
     
    113122        int leading; 
    114123        int x; 
     124        int underlinePos, underlineThickness; 
     125        int strikeoutPos, strikeoutThickness; 
    115126 
    116127        /* Justify info (malloc during computeRuns) */ 
     
    192203public this (Device device) { 
    193204    static_this(); 
    194     if (device is null) device = Device.getDevice(); 
    195     if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); 
    196     this.device = device; 
     205    super(device); 
    197206    wrapWidth = ascent = descent = -1; 
    198207    lineSpacing = 0; 
     
    201210    styles[0] = new StyleItem(); 
    202211    styles[1] = new StyleItem(); 
     212    stylesCount = 2; 
    203213    text = ""; //$NON-NLS-1$ 
    204214    void* ppv; 
     
    207217        mLangFontLink2 = ppv; 
    208218    } 
    209     if (device.tracking) device.new_Object(this); 
     219    init_(); 
    210220} 
    211221 
     
    350360                run = allRuns[--i]; 
    351361            } else  if (start <= 0 && i is lineStart) { 
    352                 i = firstIndice; 
    353                 run = allRuns[i]; 
    354                 start = Math.max(1, firstStart); 
     362                if (lineWidth is wrapWidth && firstIndice > 0) { 
     363                    i = firstIndice - 1; 
     364                    run = allRuns[i]; 
     365                    start = run.length; 
     366                } else { 
     367                    i = firstIndice; 
     368                    run = allRuns[i]; 
     369                    start = Math.max(1, firstStart); 
     370                } 
    355371            } 
    356372            breakRun(run); 
     
    472488} 
    473489 
    474 /** 
    475  * Disposes of the operating system resources associated with 
    476  * the text layout. Applications must dispose of all allocated text layouts. 
    477  */ 
    478 override public void dispose () { 
    479     if (device is null) return; 
     490void destroy () { 
    480491    freeRuns(); 
    481492    font = null; 
     
    494505    } 
    495506    OS.OleUninitialize(); 
    496     if (device.tracking) device.dispose_Object(this); 
    497     device = null; 
    498507} 
    499508 
     
    596605        if (!Gdip.Matrix_IsIdentity(matrix)) { 
    597606            lpXform = new float[6]; 
    598             Gdip.Matrix_GetElements(matrix, lpXform); 
     607            Gdip.Matrix_GetElements(matrix, lpXform.ptr); 
    599608        } 
    600609        Gdip.Matrix_delete(matrix); 
     
    643652    } 
    644653    RECT rect; 
    645     void* selBrush; 
    646     void* selPen; 
    647     void* selBrushFg; 
     654    Gdip.Brush selBrush; 
     655    Gdip.Pen selPen; 
     656    Gdip.Brush selBrushFg; 
    648657 
    649658    if (hasSelection || (flags & DWT.LAST_LINE_SELECTION) !is 0) { 
     
    652661            auto argb = ((alpha & 0xFF) << 24) | ((bg >> 16) & 0xFF) | (bg & 0xFF00) | ((bg & 0xFF) << 16); 
    653662            auto color = Gdip.Color_new(argb); 
    654             selBrush = Gdip.SolidBrush_new(color); 
     663            selBrush = cast(Gdip.Brush)Gdip.SolidBrush_new(color); 
    655664            Gdip.Color_delete(color); 
    656665            auto fg = selectionForeground.handle; 
    657666            argb = ((alpha & 0xFF) << 24) | ((fg >> 16) & 0xFF) | (fg & 0xFF00) | ((fg & 0xFF) << 16); 
    658667            color = Gdip.Color_new(argb); 
    659             selBrushFg = Gdip.SolidBrush_new(color); 
    660             selPen = Gdip.Pen_new( cast(Gdip.Brush)selBrushFg, 1); 
     668            selBrushFg = cast(Gdip.Brush)Gdip.SolidBrush_new(color); 
     669            selPen = cast(Gdip.Pen) Gdip.Pen_new( cast(Gdip.Brush)selBrushFg, 1); 
    661670            Gdip.Color_delete(color); 
    662671        } else { 
    663             selBrush = OS.CreateSolidBrush(selectionBackground.handle); 
    664             selPen = OS.CreatePen(OS.PS_SOLID, 1, selectionForeground.handle); 
     672            selBrush = cast(Gdip.Brush)OS.CreateSolidBrush(selectionBackground.handle); 
     673            selPen = cast(Gdip.Pen)OS.CreatePen(OS.PS_SOLID, 1, selectionForeground.handle); 
    665674        } 
    666675    } 
     
    671680        int drawY = y + lineY[line]; 
    672681        StyleItem[] lineRuns = runs[line]; 
    673         int lineHeight = lineY[line+1] - lineY[line]
     682        int lineHeight = lineY[line+1] - lineY[line] - lineSpacing
    674683        if (flags !is 0 && (hasSelection || (flags & DWT.LAST_LINE_SELECTION) !is 0)) { 
    675684            bool extents = false; 
     
    692701                    width = OS.IsWin95 ? 0x7FFF : 0x6FFFFFF; 
    693702                } else { 
    694                     width = (lineHeight - lineSpacing) / 3; 
     703                    width = lineHeight / 3; 
    695704                } 
    696705                if (gdip) { 
    697                     Gdip.Graphics_FillRectangle(gdipGraphics, cast(Gdip.Brush)selBrush, drawX + lineWidth[line], drawY, width, lineHeight - lineSpacing); 
     706                    Gdip.Graphics_FillRectangle(gdipGraphics, cast(Gdip.Brush)selBrush, drawX + lineWidth[line], drawY, width, lineHeight); 
    698707                } else { 
    699708                    OS.SelectObject(hdc, selBrush); 
    700                     OS.PatBlt(hdc, drawX + lineWidth[line], drawY, width, lineHeight - lineSpacing, OS.PATCOPY); 
     709                    OS.PatBlt(hdc, drawX + lineWidth[line], drawY, width, lineHeight, OS.PATCOPY); 
    701710                } 
    702711            } 
     
    705714        if (drawX + lineWidth[line] < clip.x) continue; 
    706715        int baseline = Math.max(0, this.ascent); 
     716        int lineUnderlinePos = 0; 
    707717        for (int i = 0; i < lineRuns.length; i++) { 
    708718            baseline = Math.max(baseline, lineRuns[i].ascent); 
     719            lineUnderlinePos = Math.min(lineUnderlinePos, lineRuns[i].underlinePos); 
    709720        } 
    710721        int alignmentX = drawX; 
     
    719730                    if (fullSelection) { 
    720731                        if (gdip) { 
    721                             Gdip.Graphics_FillRectangle(gdipGraphics, cast(Gdip.Brush)selBrush, drawX, drawY, run.width, lineHeight - lineSpacing); 
     732                            Gdip.Graphics_FillRectangle(gdipGraphics, cast(Gdip.Brush)selBrush, drawX, drawY, run.width, lineHeight); 
    722733                        } else { 
    723734                            OS.SelectObject(hdc, selBrush); 
    724                             OS.PatBlt(hdc, drawX, drawY, run.width, lineHeight - lineSpacing, OS.PATCOPY); 
     735                            OS.PatBlt(hdc, drawX, drawY, run.width, lineHeight, OS.PATCOPY); 
    725736                        } 
    726737                    } else { 
    727738                        if (run.style !is null && run.style.background !is null) { 
    728739                            auto bg = run.style.background.handle; 
    729                             int drawRunY = drawY + (baseline - run.ascent); 
    730740                            if (gdip) { 
    731741                                int argb = ((alpha & 0xFF) << 24) | ((bg >> 16) & 0xFF) | (bg & 0xFF00) | ((bg & 0xFF) << 16); 
    732742                                auto color = Gdip.Color_new(argb); 
    733743                                auto brush = Gdip.SolidBrush_new(color); 
    734                                 Gdip.Graphics_FillRectangle(gdipGraphics, cast(Gdip.Brush)brush, drawX, drawRunY, run.width, run.ascent + run.descent); 
     744                                Gdip.Graphics_FillRectangle(gdipGraphics, cast(Gdip.Brush)brush, drawX, drawY, run.width, lineHeight); 
    735745                                Gdip.Color_delete(color); 
    736746                                Gdip.SolidBrush_delete(brush); 
     
    738748                                auto hBrush = OS.CreateSolidBrush (bg); 
    739749                                auto oldBrush = OS.SelectObject(hdc, hBrush); 
    740                                 OS.PatBlt(hdc, drawX, drawRunY, run.width, run.ascent + run.descent, OS.PATCOPY); 
     750                                OS.PatBlt(hdc, drawX, drawY, run.width, lineHeight, OS.PATCOPY); 
    741751                                OS.SelectObject(hdc, oldBrush); 
    742752                                OS.DeleteObject(hBrush); 
     
    758768                            runX = (orientation & DWT.RIGHT_TO_LEFT) !is 0 ? run.width - piX : piX; 
    759769                            rect.right = drawX + runX; 
    760                             rect.bottom = drawY + lineHeight - lineSpacing
     770                            rect.bottom = drawY + lineHeight
    761771                            if (gdip) { 
     772                                if (rect.left > rect.right) { 
     773                                    int tmp = rect.left; 
     774                                    rect.left = rect.right; 
     775                                    rect.right = tmp; 
     776                                } 
    762777                                Gdip.Graphics_FillRectangle(gdipGraphics, cast(Gdip.Brush)selBrush, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); 
    763778                            } else { 
     
    771786            drawX += run.width; 
    772787        } 
     788        RECT* borderClip = null; 
    773789        drawX = alignmentX; 
    774790        for (int i = 0; i < lineRuns.length; i++) { 
     
    820836                            types[typeIndex] = cast(byte)newType; 
    821837                        } 
    822                         auto path = Gdip.GraphicsPath_new(cast(Gdip.Point[])points, types, count, Gdip.FillModeAlternate); 
     838                        auto path = Gdip.GraphicsPath_new(cast(Gdip.Point*)points.ptr, types.ptr, count, Gdip.FillModeAlternate); 
    823839                        if (path is null) DWT.error(DWT.ERROR_NO_HANDLES); 
    824840                        auto brush = foregroundBrush; 
     
    866882                        } 
    867883                        Gdip.Graphics_SetSmoothingMode(gdipGraphics, antialias); 
    868                         if (run.style !is null && (run.style.underline || run.style.strikeout)) { 
    869                             auto newPen = hasSelection ? cast(Gdip.Pen)selPen : Gdip.Pen_new(brush, 1); 
    870                             Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeNone); 
    871                             if (run.style.underline) { 
    872                                 int underlineY = drawY + baseline + 1 - run.style.rise; 
    873                                 Gdip.Graphics_DrawLine(gdipGraphics, newPen, drawX, underlineY, drawX + run.width, underlineY); 
    874                             } 
    875                             if (run.style.strikeout) { 
    876                                 int strikeoutY = drawRunY + run.leading + (run.ascent - run.style.rise) / 2; 
    877                                 Gdip.Graphics_DrawLine(gdipGraphics, newPen, drawX, strikeoutY, drawX + run.width, strikeoutY); 
    878                             } 
    879                             if (cast(void*)newPen !is selPen) Gdip.Pen_delete(newPen); 
    880                             Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf); 
    881                         } 
     884                        drawLines(gdip, gdipGraphics, x, drawY + baseline, lineUnderlinePos, drawY + lineHeight, lineRuns, i, brush, null, alpha); 
    882885                        if (partialSelection) { 
    883886                            Gdip.Graphics_Restore(gdipGraphics, gstate); 
     
    885888                            Gdip.Graphics_SetClip(gdipGraphics, &gdipRect, Gdip.CombineModeIntersect); 
    886889                            Gdip.Graphics_SetSmoothingMode(gdipGraphics, textAntialias); 
    887                             Gdip.Graphics_FillPath(gdipGraphics, cast(Gdip.Brush)selBrushFg, path); 
     890                            if ((data.style & DWT.MIRRORED) !is 0) { 
     891                                gstate2 = Gdip.Graphics_Save(gdipGraphics); 
     892                                Gdip.Graphics_ScaleTransform(gdipGraphics, -1, 1, Gdip.MatrixOrderPrepend); 
     893                                Gdip.Graphics_TranslateTransform(gdipGraphics, -2 * drawX - run.width, 0, Gdip.MatrixOrderPrepend); 
     894                            } 
     895                            Gdip.Graphics_FillPath(gdipGraphics, selBrushFg, path); 
     896                            if ((data.style & DWT.MIRRORED) !is 0) { 
     897                                Gdip.Graphics_Restore(gdipGraphics, gstate2); 
     898                            } 
    888899                            Gdip.Graphics_SetSmoothingMode(gdipGraphics, antialias); 
    889                             if (run.style !is null && (run.style.underline || run.style.strikeout)) { 
    890                                 Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeNone); 
    891                                 if (run.style.underline) { 
    892                                     int underlineY = drawY + baseline + 1 - run.style.rise; 
    893                                     Gdip.Graphics_DrawLine(gdipGraphics, cast(Gdip.Pen)selPen, rect.left, underlineY, rect.right, underlineY); 
    894                                 } 
    895                                 if (run.style.strikeout) { 
    896                                     int strikeoutY = drawRunY + run.leading + (run.ascent - run.style.rise) / 2; 
    897                                     Gdip.Graphics_DrawLine(gdipGraphics, cast(Gdip.Pen)selPen, rect.left, strikeoutY, rect.right, strikeoutY); 
    898                                 } 
    899                                 Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf); 
    900                             } 
     900                            drawLines(gdip, gdipGraphics, x, drawY + baseline, lineUnderlinePos, drawY + lineHeight, lineRuns, i, selBrushFg, &rect, alpha); 
    901901                            Gdip.Graphics_Restore(gdipGraphics, gstate); 
    902902                        } 
     903                        borderClip = drawBorder(gdip, gdipGraphics, x, drawY, lineHeight, foregroundBrush, selBrushFg, fullSelection, borderClip, partialSelection ? &rect : null, alpha, lineRuns, i, selectionStart, selectionEnd); 
    903904                        Gdip.GraphicsPath_delete(path); 
    904905                        if ( brush !is cast(Gdip.Brush)selBrushFg && brush !is cast(Gdip.Brush)foregroundBrush) 
    905906                            Gdip.SolidBrush_delete(cast(Gdip.SolidBrush)brush); 
    906907                    }   else { 
    907                             int fg = foreground; 
     908                            auto fg = foreground; 
    908909                            if (fullSelection) { 
    909910                                fg = selectionForeground.handle; 
     
    913914                        OS.SetTextColor(hdc, fg); 
    914915                        OS.ScriptTextOut(hdc, run.psc, drawX + offset, drawRunY, 0, null, &run.analysis , null, 0, run.glyphs, run.glyphCount, run.advances, run.justify, run.goffsets); 
    915                         if (run.style !is null && (run.style.underline || run.style.strikeout)) { 
    916                             auto newPen = hasSelection && fg is selectionForeground.handle ? cast(HPEN)selPen : OS.CreatePen(OS.PS_SOLID, 1, fg); 
    917                             auto oldPen = OS.SelectObject(hdc, newPen); 
    918                             if (run.style.underline) { 
    919                                 int underlineY = drawY + baseline + 1 - run.style.rise; 
    920                                 OS.MoveToEx(hdc, drawX, underlineY, null); 
    921                                 OS.LineTo(hdc, drawX + run.width, underlineY); 
    922                             } 
    923                             if (run.style.strikeout) { 
    924                                 int strikeoutY = drawRunY + run.leading + (run.ascent - run.style.rise) / 2; 
    925                                 OS.MoveToEx(hdc, drawX, strikeoutY, null); 
    926                                 OS.LineTo(hdc, drawX + run.width, strikeoutY); 
    927                             } 
    928                             OS.SelectObject(hdc, oldPen); 
    929                             if (!hasSelection || fg !is selectionForeground.handle) OS.DeleteObject(newPen); 
    930                         } 
     916                        drawLines(gdip, hdc, x, drawY + baseline, lineUnderlinePos, drawY + lineHeight, lineRuns, i, cast(void*)fg, null, alpha); 
    931917                        if (partialSelection && fg !is selectionForeground.handle) { 
    932918                            OS.SetTextColor(hdc, selectionForeground.handle); 
    933919                            OS.ScriptTextOut(hdc, run.psc, drawX + offset, drawRunY, OS.ETO_CLIPPED, &rect, &run.analysis , null, 0, run.glyphs, run.glyphCount, run.advances, run.justify, run.goffsets); 
    934                             if (run.style !is null && (run.style.underline || run.style.strikeout)) { 
    935                                 auto oldPen = OS.SelectObject(hdc, selPen); 
    936                                 if (run.style.underline) { 
    937                                     int underlineY = drawY + baseline + 1 - run.style.rise; 
    938                                     OS.MoveToEx(hdc, rect.left, underlineY, null); 
    939                                     OS.LineTo(hdc, rect.right, underlineY); 
    940                                 } 
    941                                 if (run.style.strikeout) { 
    942                                     int strikeoutY = drawRunY + run.leading + (run.ascent - run.style.rise) / 2; 
    943                                     OS.MoveToEx(hdc, rect.left, strikeoutY, null); 
    944                                     OS.LineTo(hdc, rect.right, strikeoutY); 
    945                                 } 
    946                                 OS.SelectObject(hdc, oldPen); 
    947                             } 
     920                            drawLines(gdip, hdc, x, drawY + baseline, lineUnderlinePos, drawY + lineHeight, lineRuns, i, cast(void*)selectionForeground.handle, &rect, alpha); 
    948921                        } 
     922                        int selForeground = selectionForeground !is null ? selectionForeground.handle : 0; 
     923                        borderClip = drawBorder(gdip, hdc, x, drawY, lineHeight, cast(void*)foreground, cast(void*)selForeground, fullSelection, borderClip, partialSelection ? &rect : null, alpha, lineRuns, i, selectionStart, selectionEnd); 
    949924                    } 
    950925                } 
     
    956931        if (selBrush !is null) Gdip.SolidBrush_delete(cast(Gdip.SolidBrush)selBrush); 
    957932        if (selBrushFg !is null) Gdip.SolidBrush_delete(cast(Gdip.SolidBrush)selBrushFg); 
    958         if (selPen !is null) Gdip.Pen_delete(cast(Gdip.Pen)selPen); 
     933        if (selPen !is null) Gdip.Pen_delete(selPen); 
    959934    } else { 
    960935        OS.RestoreDC(hdc, state); 
     
    965940} 
    966941 
     942void drawLines(bool advance, void* graphics, int x, int lineBaseline, int lineUnderlinePos, int lineBottom, StyleItem[] line, int index, void* color, RECT* clipRect, int alpha) { 
     943    StyleItem run = line[index]; 
     944    TextStyle style = run.style; 
     945    if (style is null) return; 
     946    if (!style.underline && !style.strikeout) return; 
     947    int runX = x + run.x; 
     948    int underlineY = lineBaseline - lineUnderlinePos; 
     949    int strikeoutY = lineBaseline - run.strikeoutPos; 
     950    if (advance) { 
     951        Gdip.Graphics_SetPixelOffsetMode(cast(Gdip.Graphics)graphics, Gdip.PixelOffsetModeNone); 
     952        auto brush = color; 
     953        if (style.underline) { 
     954            if (style.underlineColor !is null) { 
     955                int fg = style.underlineColor.handle; 
     956                int argb = ((alpha & 0xFF) << 24) | ((fg >> 16) & 0xFF) | (fg & 0xFF00) | ((fg & 0xFF) << 16); 
     957                auto gdiColor = Gdip.Color_new(argb); 
     958                brush = Gdip.SolidBrush_new(gdiColor); 
     959                Gdip.Color_delete(gdiColor); 
     960            } 
     961            switch (style.underlineStyle) { 
     962                case DWT.UNDERLINE_SQUIGGLE: 
     963                case DWT.UNDERLINE_ERROR: { 
     964                    int squigglyThickness = 1; 
     965                    int squigglyHeight = 2 * squigglyThickness; 
     966                    int squigglyY = Math.min(underlineY - squigglyHeight / 2, lineBottom - squigglyHeight - 1); 
     967                    int squigglyX = runX; 
     968                    for (int i = index; i > 0 && style.isAdherentUnderline(line[i - 1].style); i--) { 
     969                        squigglyX = x + line[i - 1].x; 
     970                    } 
     971                    int gstate = 0; 
     972                    if (clipRect is null) { 
     973                        gstate = Gdip.Graphics_Save(cast(Gdip.Graphics)graphics); 
     974                        Gdip.Rect gdipRect; 
     975                        gdipRect.X = runX; 
     976                        gdipRect.Y = squigglyY; 
     977                        gdipRect.Width = run.width + 1; 
     978                        gdipRect.Height = squigglyY + squigglyHeight + 1; 
     979                        Gdip.Graphics_SetClip(cast(Gdip.Graphics)graphics, &gdipRect, Gdip.CombineModeIntersect); 
     980                    } 
     981                    int[] points = computePolyline(squigglyX, squigglyY, runX + run.width, squigglyY + squigglyHeight); 
     982                    auto pen = Gdip.Pen_new(cast(Gdip.Brush)brush, squigglyThickness); 
     983                    Gdip.Graphics_DrawLines(cast(Gdip.Graphics)graphics, pen, cast(Gdip.Point*)points.ptr, points.length / 2); 
     984                    Gdip.Pen_delete(pen); 
     985                    if (gstate !is 0) Gdip.Graphics_Restore(cast(Gdip.Graphics)graphics, gstate); 
     986                    break; 
     987                } 
     988                case DWT.UNDERLINE_SINGLE: 
     989                    Gdip.Graphics_FillRectangle(cast(Gdip.Graphics)graphics, cast(Gdip.Brush)brush, runX, underlineY, run.width, run.underlineThickness); 
     990                    break; 
     991                case DWT.UNDERLINE_DOUBLE: 
     992                    Gdip.Graphics_FillRectangle(cast(Gdip.Graphics)graphics, cast(Gdip.Brush)brush, runX, underlineY, run.width, run.underlineThickness); 
     993                    Gdip.Graphics_FillRectangle(cast(Gdip.Graphics)graphics, cast(Gdip.Brush)brush, runX, underlineY + run.underlineThickness * 2, run.width, run.underlineThickness); 
     994                    break; 
     995                case UNDERLINE_IME_THICK: 
     996                    Gdip.Graphics_FillRectangle(cast(Gdip.Graphics)graphics, cast(Gdip.Brush)brush, runX - run.underlineThickness, underlineY, run.width, run.underlineThickness * 2); 
     997                    break; 
     998                case UNDERLINE_IME_DOT: 
     999                case UNDERLINE_IME_DASH: { 
     1000                    auto pen = Gdip.Pen_new(cast(Gdip.Brush)brush, 1); 
     1001                    int dashStyle = style.underlineStyle is UNDERLINE_IME_DOT ? Gdip.DashStyleDot : Gdip.DashStyleDash; 
     1002                    Gdip.Pen_SetDashStyle(pen, dashStyle); 
     1003                    Gdip.Graphics_DrawLine(cast(Gdip.Graphics)graphics, pen, runX, underlineY, runX + run.width, underlineY); 
     1004                    Gdip.Pen_delete(pen); 
     1005                    break; 
     1006                } 
     1007            } 
     1008            if (brush !is color) Gdip.SolidBrush_delete(cast(Gdip.SolidBrush)brush); 
     1009        } 
     1010        if (style.strikeout) { 
     1011            if (style.strikeoutColor !is null) { 
     1012                int fg = style.strikeoutColor.handle; 
     1013                int argb = ((alpha & 0xFF) << 24) | ((fg >> 16) & 0xFF) | (fg & 0xFF00) | ((fg & 0xFF) << 16); 
     1014                auto gdiColor = Gdip.Color_new(argb); 
     1015                brush = Gdip.SolidBrush_new(gdiColor); 
     1016                Gdip.Color_delete(gdiColor); 
     1017            } 
     1018            Gdip.Graphics_FillRectangle(cast(Gdip.Graphics)graphics, cast(Gdip.Brush)brush, runX, strikeoutY, run.width, run.strikeoutThickness); 
     1019            if (brush !is color) Gdip.SolidBrush_delete(cast(Gdip.SolidBrush)brush); 
     1020        } 
     1021        Gdip.Graphics_SetPixelOffsetMode(cast(Gdip.Graphics)graphics, Gdip.PixelOffsetModeHalf); 
     1022    } else { 
     1023        uint colorRefUnderline = cast(uint)color; 
     1024        uint colorRefStrikeout = cast(uint)color; 
     1025        int /*long*/ brushUnderline = 0; 
     1026        int /*long*/ brushStrikeout = 0; 
     1027        RECT rect; 
     1028        if (style.underline) { 
     1029            if (style.underlineColor !is null) { 
     1030                colorRefUnderline = style.underlineColor.handle; 
     1031            } 
     1032            switch (style.underlineStyle) { 
     1033                case DWT.UNDERLINE_SQUIGGLE: 
     1034                case DWT.UNDERLINE_ERROR: { 
     1035                    int squigglyThickness = 1; 
     1036                    int squigglyHeight = 2 * squigglyThickness; 
     1037                    int squigglyY = Math.min(underlineY - squigglyHeight / 2, lineBottom - squigglyHeight - 1); 
     1038                    int squigglyX = runX; 
     1039                    for (int i = index; i > 0 && style.isAdherentUnderline(line[i - 1].style); i--) { 
     1040                        squigglyX = x + line[i - 1].x; 
     1041                    } 
     1042                    int state = OS.SaveDC(graphics); 
     1043                    if (clipRect !is null) { 
     1044                        OS.IntersectClipRect(graphics, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom); 
     1045                    } else { 
     1046                        OS.IntersectClipRect(graphics, runX, squigglyY, runX + run.width + 1, squigglyY + squigglyHeight + 1); 
     1047                    } 
     1048                    int[] points = computePolyline(squigglyX, squigglyY, runX + run.width, squigglyY + squigglyHeight); 
     1049                    auto pen = OS.CreatePen(OS.PS_SOLID, squigglyThickness, colorRefUnderline); 
     1050                    auto oldPen = OS.SelectObject(graphics, pen); 
     1051                    OS.Polyline(graphics, cast(POINT*)points.ptr, points.length / 2); 
     1052                    int length_ = points.length; 
     1053                    if (length_ >= 2 && squigglyThickness <= 1) { 
     1054                        OS.SetPixel (graphics, points[length_ - 2], points[length_ - 1], colorRefUnderline); 
     1055                    } 
     1056                    OS.RestoreDC(graphics, state); 
     1057                    OS.SelectObject(graphics, oldPen); 
     1058                    OS.DeleteObject(pen); 
     1059                    break; 
     1060                } 
     1061                case DWT.UNDERLINE_SINGLE: 
     1062                    brushUnderline = cast(uint) OS.CreateSolidBrush(colorRefUnderline); 
     1063                    OS.SetRect(&rect, runX, underlineY, runX + run.width, underlineY + run.underlineThickness); 
     1064                    if (clipRect !is null) { 
     1065                        rect.left = Math.max(rect.left, clipRect.left); 
     1066                        rect.right = Math.min(rect.right, clipRect.right); 
     1067                    } 
     1068                    OS.FillRect(graphics, &rect, cast(void*)brushUnderline); 
     1069                    break; 
     1070                case DWT.UNDERLINE_DOUBLE: 
     1071                    brushUnderline = cast(uint)OS.CreateSolidBrush(colorRefUnderline); 
     1072                    OS.SetRect(&rect, runX, underlineY, runX + run.width, underlineY + run.underlineThickness); 
     1073                    if (clipRect !is null) { 
     1074                        rect.left = Math.max(rect.left, clipRect.left); 
     1075                        rect.right = Math.min(rect.right, clipRect.right); 
     1076                    } 
     1077                    OS.FillRect(graphics, &rect, cast(void*)brushUnderline); 
     1078                    OS.SetRect(&rect, runX, underlineY + run.underlineThickness * 2, runX + run.width, underlineY + run.underlineThickness * 3); 
     1079                    if (clipRect !is null) { 
     1080                        rect.left = Math.max(rect.left, clipRect.left); 
     1081                        rect.right = Math.min(rect.right, clipRect.right); 
     1082                    } 
     1083                    OS.FillRect(graphics, &rect,  cast(void*)brushUnderline); 
     1084                    break; 
     1085                case UNDERLINE_IME_THICK: 
     1086                    brushUnderline = cast(uint)OS.CreateSolidBrush(colorRefUnderline); 
     1087                    OS.SetRect(&rect, runX, underlineY - run.underlineThickness, runX + run.width, underlineY + run.underlineThickness); 
     1088                    if (clipRect !is null) { 
     1089                        rect.left = Math.max(rect.left, clipRect.left); 
     1090                        rect.right = Math.min(rect.right, clipRect.right); 
     1091                    } 
     1092                    OS.FillRect(graphics, &rect,  cast(void*)brushUnderline); 
     1093                    break; 
     1094                case UNDERLINE_IME_DASH: 
     1095                case UNDERLINE_IME_DOT: { 
     1096                    underlineY = lineBaseline + run.descent; 
     1097                    int penStyle = style.underlineStyle is UNDERLINE_IME_DASH ? OS.PS_DASH : OS.PS_DOT; 
     1098                    auto pen = OS.CreatePen(penStyle, 1, colorRefUnderline); 
     1099                    auto oldPen = OS.SelectObject(graphics, pen); 
     1100                    OS.SetRect(&rect, runX, underlineY, runX + run.width, underlineY + run.underlineThickness); 
     1101                    if (clipRect !is null) { 
     1102                        rect.left = Math.max(rect.left, clipRect.left); 
     1103                        rect.right = Math.min(rect.right, clipRect.right); 
     1104                    } 
     1105                    OS.MoveToEx(graphics, rect.left, rect.top, null); 
     1106                    OS.LineTo(graphics, rect.right, rect.top); 
     1107                    OS.SelectObject(graphics, oldPen); 
     1108                    OS.DeleteObject(pen); 
     1109                    break; 
     1110                } 
     1111            } 
     1112        } 
     1113        if (style.strikeout) { 
     1114            if (style.strikeoutColor !is null) { 
     1115                colorRefStrikeout = style.strikeoutColor.handle; 
     1116            } 
     1117            if (brushUnderline !is 0 && colorRefStrikeout is colorRefUnderline) { 
     1118                brushStrikeout = brushUnderline; 
     1119            } else { 
     1120                brushStrikeout = cast(int) OS.CreateSolidBrush(colorRefStrikeout); 
     1121            } 
     1122            OS.SetRect(&rect, runX, strikeoutY, runX + run.width, strikeoutY + run.strikeoutThickness); 
     1123            if (clipRect !is null) { 
     1124                rect.left = Math.max(rect.left, clipRect.left); 
     1125                rect.right = Math.min(rect.right, clipRect.right); 
     1126            } 
     1127            OS.FillRect(graphics, &rect, cast(void*)brushStrikeout); 
     1128        } 
     1129        if (brushUnderline !is 0) OS.DeleteObject(cast(void*)brushUnderline); 
     1130        if (brushStrikeout !is 0 && brushStrikeout !is brushUnderline) OS.DeleteObject(cast(void*)brushStrikeout); 
     1131    } 
     1132} 
     1133 
     1134RECT* drawBorder(bool advance, void* graphics, int x, int y, int lineHeight, void* color, void* selectionColor, bool fullSelection, RECT* clipRect, RECT* rect, int alpha, StyleItem[] line, int index, int selectionStart, int selectionEnd) { 
     1135    StyleItem run = line[index]; 
     1136    TextStyle style = run.style; 
     1137    if (style is null) return null; 
     1138    if (style.borderStyle is DWT.NONE) return null; 
     1139    if (rect !is null) { 
     1140        if (clipRect is null) { 
     1141            clipRect = new RECT (); 
     1142            OS.SetRect(clipRect, -1, rect.top, -1, rect.bottom); 
     1143        } 
     1144        bool isRTL = (orientation & DWT.RIGHT_TO_LEFT) !is 0; 
     1145        if (run.start <= selectionStart && selectionStart <= run.start + run.length) { 
     1146            if (run.analysis.fRTL ^ isRTL) { 
     1147                clipRect.right = rect.left; 
     1148            } else { 
     1149                clipRect.left = rect.left; 
     1150            } 
     1151        } 
     1152        if (run.start <= selectionEnd && selectionEnd <= run.start + run.length) { 
     1153            if (run.analysis.fRTL ^ isRTL) { 
     1154                clipRect.left = rect.right; 
     1155            } else { 
     1156                clipRect.right = rect.right; 
     1157            } 
     1158        } 
     1159    } 
     1160    if (index + 1 >= line.length || !style.isAdherentBorder(line[index + 1].style)) { 
     1161        int left = run.x; 
     1162        for (int i = index; i > 0 && style.isAdherentBorder(line[i - 1].style); i--) { 
     1163            left = line[i - 1].x; 
     1164        } 
     1165        if (advance) { 
     1166            auto brush = color; 
     1167            int customColor = -1; 
     1168            if (style.borderColor !is null) { 
     1169                customColor = style.borderColor.handle; 
     1170            } else { 
     1171                if (style.foreground !is null) { 
     1172                    customColor = style.foreground.handle; 
     1173                } 
     1174                if (fullSelection && clipRect is null) { 
     1175                    customColor = -1; 
     1176                    brush = selectionColor; 
     1177                } 
     1178            } 
     1179            if (customColor !is -1) { 
     1180                int argb = ((alpha & 0xFF) << 24) | ((customColor >> 16) & 0xFF) | (customColor & 0xFF00) | ((customColor & 0xFF) << 16); 
     1181                auto gdiColor = Gdip.Color_new(argb); 
     1182                brush = Gdip.SolidBrush_new(gdiColor); 
     1183                Gdip.Color_delete(gdiColor); 
     1184            } 
     1185            int lineWidth = 1; 
     1186            int lineStyle = Gdip.DashStyleSolid; 
     1187            switch (style.borderStyle) { 
     1188                case DWT.BORDER_SOLID: break; 
     1189                case DWT.BORDER_DASH: lineStyle = Gdip.DashStyleDash; break; 
     1190                case DWT.BORDER_DOT: lineStyle = Gdip.DashStyleDot; break; 
     1191            } 
     1192            auto pen = Gdip.Pen_new(cast(Gdip.Brush)brush, lineWidth); 
     1193            Gdip.Pen_SetDashStyle(pen, lineStyle); 
     1194            float gdipXOffset = 0.5f, gdipYOffset = 0.5f; 
     1195            Gdip.Graphics_TranslateTransform(cast(Gdip.Graphics)graphics, gdipXOffset, gdipYOffset, Gdip.MatrixOrderPrepend); 
     1196            if (style.borderColor is null && clipRect !is null) { 
     1197                int gstate = Gdip.Graphics_Save(cast(Gdip.Graphics)graphics); 
     1198                if (clipRect.left is -1) clipRect.left = 0; 
     1199                if (clipRect.right is -1) clipRect.right = 0x7ffff; 
     1200                Gdip.Rect gdipRect; 
     1201                gdipRect.X = clipRect.left; 
     1202                gdipRect.Y = clipRect.top; 
     1203                gdipRect.Width = clipRect.right - clipRect.left; 
     1204                gdipRect.Height = clipRect.bottom - clipRect.top; 
     1205                Gdip.Graphics_SetClip(cast(Gdip.Graphics)graphics, &gdipRect, Gdip.CombineModeExclude); 
     1206                Gdip.Graphics_DrawRectangle(cast(Gdip.Graphics)graphics, pen, x + left, y, run.x + run.width - left - 1, lineHeight - 1); 
     1207                Gdip.Graphics_Restore(cast(Gdip.Graphics)graphics, gstate); 
     1208                gstate = Gdip.Graphics_Save(cast(Gdip.Graphics)graphics); 
     1209                Gdip.Graphics_SetClip(cast(Gdip.Graphics)graphics, &gdipRect, Gdip.CombineModeIntersect); 
     1210                auto selPen = Gdip.Pen_new(cast(Gdip.Brush)selectionColor, lineWidth); 
     1211                Gdip.Pen_SetDashStyle(pen, lineStyle); 
     1212                Gdip.Graphics_DrawRectangle(cast(Gdip.Graphics)graphics, selPen, x + left, y, run.x + run.width - left - 1, lineHeight - 1); 
     1213                Gdip.Pen_delete(selPen); 
     1214                Gdip.Graphics_Restore(cast(Gdip.Graphics)graphics, gstate); 
     1215            } else { 
     1216                Gdip.Graphics_DrawRectangle(cast(Gdip.Graphics)graphics, pen, x + left, y, run.x + run.width - left - 1, lineHeight - 1); 
     1217            } 
     1218            Gdip.Graphics_TranslateTransform(cast(Gdip.Graphics)graphics, -gdipXOffset, -gdipYOffset, Gdip.MatrixOrderPrepend); 
     1219            Gdip.Pen_delete(pen); 
     1220            if (customColor !is -1) Gdip.SolidBrush_delete(cast(Gdip.SolidBrush)brush); 
     1221        } else { 
     1222            if (style.borderColor !is null) { 
     1223                color = cast(void*)style.borderColor.handle; 
     1224            } else { 
     1225                if (style.foreground !is null) { 
     1226                    color = cast(void*)style.foreground.handle; 
     1227                } 
     1228                if (fullSelection && clipRect is null) { 
     1229                    color = selectionColor; 
     1230                } 
     1231            } 
     1232            int lineWidth = 1; 
     1233            int lineStyle = OS.PS_SOLID; 
     1234            switch (style.borderStyle) { 
     1235                case DWT.BORDER_SOLID: break; 
     1236                case DWT.BORDER_DASH: lineStyle = OS.PS_DASH; break; 
     1237                case DWT.BORDER_DOT: lineStyle = OS.PS_DOT; break; 
     1238            } 
     1239            LOGBRUSH logBrush; 
     1240            logBrush.lbStyle = OS.BS_SOLID; 
     1241            logBrush.lbColor = cast(uint)color; 
     1242            auto newPen = OS.ExtCreatePen(lineStyle | OS.PS_GEOMETRIC, Math.max(1, lineWidth), &logBrush, 0, null); 
     1243            auto oldPen = OS.SelectObject(graphics, newPen); 
     1244            auto oldBrush = OS.SelectObject(graphics, OS.GetStockObject(OS.NULL_BRUSH)); 
     1245            OS.Rectangle(graphics, x + left, y, x + run.x + run.width, y + lineHeight); 
     1246            if (style.borderColor is null && clipRect !is null && color !is selectionColor) { 
     1247                int state = OS.SaveDC(graphics); 
     1248                if (clipRect.left is -1) clipRect.left = 0; 
     1249                if (clipRect.right is -1) clipRect.right = 0x7ffff; 
     1250                OS.IntersectClipRect(graphics, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom); 
     1251                logBrush.lbColor = cast(uint)selectionColor; 
     1252                auto selPen = OS.ExtCreatePen (lineStyle | OS.PS_GEOMETRIC, Math.max(1, lineWidth), &logBrush, 0, null); 
     1253                OS.SelectObject(graphics, selPen); 
     1254                OS.Rectangle(graphics, x + left, y, x + run.x + run.width, y + lineHeight); 
     1255                OS.RestoreDC(graphics, state); 
     1256                OS.SelectObject(graphics, newPen); 
     1257                OS.DeleteObject(selPen); 
     1258            } 
     1259            OS.SelectObject(graphics, oldBrush); 
     1260            OS.SelectObject(graphics, oldPen); 
     1261            OS.DeleteObject(newPen); 
     1262        } 
     1263        return null; 
     1264    } 
     1265    return clipRect; 
     1266} 
     1267 
     1268int[] computePolyline(int left, int top, int right, int bottom) { 
     1269    int height = bottom - top; // can be any number 
     1270    int width = 2 * height; // must be even 
     1271    int peaks = Compatibility.ceil(right - left, width); 
     1272    if (peaks is 0 && right - left > 2) { 
     1273        peaks = 1; 
     1274    } 
     1275    int length_ = ((2 * peaks) + 1) * 2; 
     1276    if (length_ < 0) return new int[0]; 
     1277 
     1278    int[] coordinates = new int[length_]; 
     1279    for (int i = 0; i < peaks; i++) { 
     1280        int index = 4 * i; 
     1281        coordinates[index] = left + (width * i); 
     1282        coordinates[index+1] = bottom; 
     1283        coordinates[index+2] = coordinates[index] + width / 2; 
     1284        coordinates[index+3] = top; 
     1285    } 
     1286    coordinates[length_-2] = left + (width * peaks); 
     1287    coordinates[length_-1] = bottom; 
     1288    return coordinates; 
     1289} 
     1290 
    9671291void freeRuns () { 
    9681292    if (allRuns is null) return; 
     
    10121336 
    10131337/** 
    1014  * Returns the bounds of the receiver. 
     1338 * Returns the bounds of the receiver. The width returned is either the 
     1339 * width of the longest line or the width set using {@link TextLayout#setWidth(int)}. 
     1340 * To obtain the text bounds of a line use {@link TextLayout#getLineBounds(int)}. 
    10151341 * 
    10161342 * @return the bounds of the receiver 
     
    10191345 *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 
    10201346 * </ul> 
     1347 * 
     1348 * @see #setWidth(int) 
     1349 * @see #getLineBounds(int) 
    10211350 */ 
    10221351public Rectangle getBounds () { 
     
    10511380    checkLayout(); 
    10521381    computeRuns(null); 
    1053     int length = text.length; 
    1054     if (length is 0) return new Rectangle(0, 0, 0, 0); 
     1382    int length_ = text.length; 
     1383    if (length_ is 0) return new Rectangle(0, 0, 0, 0); 
    10551384    if (start > end) return new Rectangle(0, 0, 0, 0); 
    1056     start = Math.min(Math.max(0, start), length - 1); 
    1057     end = Math.min(Math.max(0, end), length - 1); 
     1385    start = Math.min(Math.max(0, start), length_ - 1); 
     1386    end = Math.min(Math.max(0, end), length_ - 1); 
    10581387    start = translateOffset(start); 
    10591388    end = translateOffset(end); 
     
    11881517        return this.font.handle; 
    11891518    } 
    1190     return device.systemFont
     1519    return device.systemFont.handle
    11911520} 
    11921521 
     
    12081537    checkLayout(); 
    12091538    computeRuns(null); 
    1210     int length = text.length; 
    1211     if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE); 
     1539    int length_ = text.length; 
     1540    if (!(0 <= offset && offset <= length_)) DWT.error(DWT.ERROR_INVALID_RANGE); 
    12121541    offset = translateOffset(offset); 
    12131542    for (int i=1; i<allRuns.length; i++) { 
     
    13071636    checkLayout(); 
    13081637    computeRuns(null); 
    1309     int length = text.length; 
    1310     if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE); 
     1638    int length_ = text.length; 
     1639    if (!(0 <= offset && offset <= length_)) DWT.error(DWT.ERROR_INVALID_RANGE); 
    13111640    offset = translateOffset(offset); 
    13121641    for (int line=0; line<runs.length; line++) { 
     
    13381667    auto srcHdc = OS.CreateCompatibleDC(hDC); 
    13391668    TEXTMETRIC lptm; 
    1340     OS.SelectObject(srcHdc, font !is null ? font.handle : device.systemFont); 
     1669    OS.SelectObject(srcHdc, font !is null ? font.handle : device.systemFont.handle);