Changeset 213:36f5cb12e1a2 for dwt/graphics/TextLayout.d
- Timestamp:
- 05/17/08 11:34:28 (8 months ago)
- Files:
-
- dwt/graphics/TextLayout.d (modified) (63 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
dwt/graphics/TextLayout.d
r212 r213 17 17 import dwt.internal.Compatibility; 18 18 import dwt.internal.gdip.Gdip; 19 19 20 import dwt.internal.win32.OS; 20 21 … … 52 53 */ 53 54 public final class TextLayout : Resource { 55 alias Resource.init_ init_; 56 54 57 Font font; 55 58 String text, segmentsText; … … 64 67 int[] segments; 65 68 StyleItem[] styles; 69 int stylesCount; 66 70 67 71 StyleItem[] allRuns; … … 90 94 } 91 95 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 92 101 class StyleItem { 93 102 TextStyle style; … … 113 122 int leading; 114 123 int x; 124 int underlinePos, underlineThickness; 125 int strikeoutPos, strikeoutThickness; 115 126 116 127 /* Justify info (malloc during computeRuns) */ … … 192 203 public this (Device device) { 193 204 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); 197 206 wrapWidth = ascent = descent = -1; 198 207 lineSpacing = 0; … … 201 210 styles[0] = new StyleItem(); 202 211 styles[1] = new StyleItem(); 212 stylesCount = 2; 203 213 text = ""; //$NON-NLS-1$ 204 214 void* ppv; … … 207 217 mLangFontLink2 = ppv; 208 218 } 209 i f (device.tracking) device.new_Object(this);219 init_(); 210 220 } 211 221 … … 350 360 run = allRuns[--i]; 351 361 } 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 } 355 371 } 356 372 breakRun(run); … … 472 488 } 473 489 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; 490 void destroy () { 480 491 freeRuns(); 481 492 font = null; … … 494 505 } 495 506 OS.OleUninitialize(); 496 if (device.tracking) device.dispose_Object(this);497 device = null;498 507 } 499 508 … … 596 605 if (!Gdip.Matrix_IsIdentity(matrix)) { 597 606 lpXform = new float[6]; 598 Gdip.Matrix_GetElements(matrix, lpXform );607 Gdip.Matrix_GetElements(matrix, lpXform.ptr); 599 608 } 600 609 Gdip.Matrix_delete(matrix); … … 643 652 } 644 653 RECT rect; 645 void*selBrush;646 void*selPen;647 void*selBrushFg;654 Gdip.Brush selBrush; 655 Gdip.Pen selPen; 656 Gdip.Brush selBrushFg; 648 657 649 658 if (hasSelection || (flags & DWT.LAST_LINE_SELECTION) !is 0) { … … 652 661 auto argb = ((alpha & 0xFF) << 24) | ((bg >> 16) & 0xFF) | (bg & 0xFF00) | ((bg & 0xFF) << 16); 653 662 auto color = Gdip.Color_new(argb); 654 selBrush = Gdip.SolidBrush_new(color);663 selBrush = cast(Gdip.Brush)Gdip.SolidBrush_new(color); 655 664 Gdip.Color_delete(color); 656 665 auto fg = selectionForeground.handle; 657 666 argb = ((alpha & 0xFF) << 24) | ((fg >> 16) & 0xFF) | (fg & 0xFF00) | ((fg & 0xFF) << 16); 658 667 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); 661 670 Gdip.Color_delete(color); 662 671 } 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); 665 674 } 666 675 } … … 671 680 int drawY = y + lineY[line]; 672 681 StyleItem[] lineRuns = runs[line]; 673 int lineHeight = lineY[line+1] - lineY[line] ;682 int lineHeight = lineY[line+1] - lineY[line] - lineSpacing; 674 683 if (flags !is 0 && (hasSelection || (flags & DWT.LAST_LINE_SELECTION) !is 0)) { 675 684 bool extents = false; … … 692 701 width = OS.IsWin95 ? 0x7FFF : 0x6FFFFFF; 693 702 } else { 694 width = (lineHeight - lineSpacing)/ 3;703 width = lineHeight / 3; 695 704 } 696 705 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); 698 707 } else { 699 708 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); 701 710 } 702 711 } … … 705 714 if (drawX + lineWidth[line] < clip.x) continue; 706 715 int baseline = Math.max(0, this.ascent); 716 int lineUnderlinePos = 0; 707 717 for (int i = 0; i < lineRuns.length; i++) { 708 718 baseline = Math.max(baseline, lineRuns[i].ascent); 719 lineUnderlinePos = Math.min(lineUnderlinePos, lineRuns[i].underlinePos); 709 720 } 710 721 int alignmentX = drawX; … … 719 730 if (fullSelection) { 720 731 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); 722 733 } else { 723 734 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); 725 736 } 726 737 } else { 727 738 if (run.style !is null && run.style.background !is null) { 728 739 auto bg = run.style.background.handle; 729 int drawRunY = drawY + (baseline - run.ascent);730 740 if (gdip) { 731 741 int argb = ((alpha & 0xFF) << 24) | ((bg >> 16) & 0xFF) | (bg & 0xFF00) | ((bg & 0xFF) << 16); 732 742 auto color = Gdip.Color_new(argb); 733 743 auto brush = Gdip.SolidBrush_new(color); 734 Gdip.Graphics_FillRectangle(gdipGraphics, cast(Gdip.Brush)brush, drawX, draw RunY, run.width, run.ascent + run.descent);744 Gdip.Graphics_FillRectangle(gdipGraphics, cast(Gdip.Brush)brush, drawX, drawY, run.width, lineHeight); 735 745 Gdip.Color_delete(color); 736 746 Gdip.SolidBrush_delete(brush); … … 738 748 auto hBrush = OS.CreateSolidBrush (bg); 739 749 auto oldBrush = OS.SelectObject(hdc, hBrush); 740 OS.PatBlt(hdc, drawX, draw RunY, run.width, run.ascent + run.descent, OS.PATCOPY);750 OS.PatBlt(hdc, drawX, drawY, run.width, lineHeight, OS.PATCOPY); 741 751 OS.SelectObject(hdc, oldBrush); 742 752 OS.DeleteObject(hBrush); … … 758 768 runX = (orientation & DWT.RIGHT_TO_LEFT) !is 0 ? run.width - piX : piX; 759 769 rect.right = drawX + runX; 760 rect.bottom = drawY + lineHeight - lineSpacing;770 rect.bottom = drawY + lineHeight; 761 771 if (gdip) { 772 if (rect.left > rect.right) { 773 int tmp = rect.left; 774 rect.left = rect.right; 775 rect.right = tmp; 776 } 762 777 Gdip.Graphics_FillRectangle(gdipGraphics, cast(Gdip.Brush)selBrush, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); 763 778 } else { … … 771 786 drawX += run.width; 772 787 } 788 RECT* borderClip = null; 773 789 drawX = alignmentX; 774 790 for (int i = 0; i < lineRuns.length; i++) { … … 820 836 types[typeIndex] = cast(byte)newType; 821 837 } 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); 823 839 if (path is null) DWT.error(DWT.ERROR_NO_HANDLES); 824 840 auto brush = foregroundBrush; … … 866 882 } 867 883 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); 882 885 if (partialSelection) { 883 886 Gdip.Graphics_Restore(gdipGraphics, gstate); … … 885 888 Gdip.Graphics_SetClip(gdipGraphics, &gdipRect, Gdip.CombineModeIntersect); 886 889 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 } 888 899 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); 901 901 Gdip.Graphics_Restore(gdipGraphics, gstate); 902 902 } 903 borderClip = drawBorder(gdip, gdipGraphics, x, drawY, lineHeight, foregroundBrush, selBrushFg, fullSelection, borderClip, partialSelection ? &rect : null, alpha, lineRuns, i, selectionStart, selectionEnd); 903 904 Gdip.GraphicsPath_delete(path); 904 905 if ( brush !is cast(Gdip.Brush)selBrushFg && brush !is cast(Gdip.Brush)foregroundBrush) 905 906 Gdip.SolidBrush_delete(cast(Gdip.SolidBrush)brush); 906 907 } else { 907 intfg = foreground;908 auto fg = foreground; 908 909 if (fullSelection) { 909 910 fg = selectionForeground.handle; … … 913 914 OS.SetTextColor(hdc, fg); 914 915 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); 931 917 if (partialSelection && fg !is selectionForeground.handle) { 932 918 OS.SetTextColor(hdc, selectionForeground.handle); 933 919 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); 948 921 } 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); 949 924 } 950 925 } … … 956 931 if (selBrush !is null) Gdip.SolidBrush_delete(cast(Gdip.SolidBrush)selBrush); 957 932 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); 959 934 } else { 960 935 OS.RestoreDC(hdc, state); … … 965 940 } 966 941 942 void 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 1134 RECT* 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 1268 int[] 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 967 1291 void freeRuns () { 968 1292 if (allRuns is null) return; … … 1012 1336 1013 1337 /** 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)}. 1015 1341 * 1016 1342 * @return the bounds of the receiver … … 1019 1345 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 1020 1346 * </ul> 1347 * 1348 * @see #setWidth(int) 1349 * @see #getLineBounds(int) 1021 1350 */ 1022 1351 public Rectangle getBounds () { … … 1051 1380 checkLayout(); 1052 1381 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); 1055 1384 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); 1058 1387 start = translateOffset(start); 1059 1388 end = translateOffset(end); … … 1188 1517 return this.font.handle; 1189 1518 } 1190 return device.systemFont ;1519 return device.systemFont.handle; 1191 1520 } 1192 1521 … … 1208 1537 checkLayout(); 1209 1538 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); 1212 1541 offset = translateOffset(offset); 1213 1542 for (int i=1; i<allRuns.length; i++) { … … 1307 1636 checkLayout(); 1308 1637 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); 1311 1640 offset = translateOffset(offset); 1312 1641 for (int line=0; line<runs.length; line++) { … … 1338 1667 auto srcHdc = OS.CreateCompatibleDC(hDC); 1339 1668 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);
