diff options
author | nyamatongwe <devnull@localhost> | 2011-08-11 10:32:39 +1000 |
---|---|---|
committer | nyamatongwe <devnull@localhost> | 2011-08-11 10:32:39 +1000 |
commit | f09627bdb8c597bcc8055b6ce370062a06ad1c37 (patch) | |
tree | 559530ca5161394842d67a1677950f1b3863e75c | |
parent | 6860b289d19541ccb8d5be31c81c0f1aa992e9d7 (diff) | |
download | scintilla-mirror-f09627bdb8c597bcc8055b6ce370062a06ad1c37.tar.gz |
Implemented parallel stacks for GDI and DirectWrite. GDI works
but DirectWrite does not draw well and eventuall crashes.
-rw-r--r-- | include/Scintilla.h | 2 | ||||
-rw-r--r-- | include/Scintilla.iface | 2 | ||||
-rw-r--r-- | src/FontQuality.h | 3 | ||||
-rw-r--r-- | win32/PlatWin.cxx | 875 | ||||
-rw-r--r-- | win32/ScintillaWin.cxx | 53 |
5 files changed, 813 insertions, 122 deletions
diff --git a/include/Scintilla.h b/include/Scintilla.h index 0aec0c8df..c8ffba04e 100644 --- a/include/Scintilla.h +++ b/include/Scintilla.h @@ -828,7 +828,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_SCROLLTOSTART 2628 #define SCI_SCROLLTOEND 2629 #define SC_TECHNOLOGY_DEFAULT 0 -#define SC_TECHNOLOGY_DIRECTWRITE 0 +#define SC_TECHNOLOGY_DIRECTWRITE 1 #define SCI_SETTECHNOLOGY 2630 #define SCI_GETTECHNOLOGY 2631 #define SCI_STARTRECORD 3001 diff --git a/include/Scintilla.iface b/include/Scintilla.iface index a578bf3fc..c5b58caae 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -2195,7 +2195,7 @@ fun void ScrollToStart=2628(,) fun void ScrollToEnd=2629(,) val SC_TECHNOLOGY_DEFAULT=0 -val SC_TECHNOLOGY_DIRECTWRITE=0 +val SC_TECHNOLOGY_DIRECTWRITE=1 # Set the technolgy used. set void SetTechnology=2630(int technology,) diff --git a/src/FontQuality.h b/src/FontQuality.h index 2c8d548a8..dc6f28b4c 100644 --- a/src/FontQuality.h +++ b/src/FontQuality.h @@ -10,3 +10,6 @@ #define SC_EFF_QUALITY_NON_ANTIALIASED 1 #define SC_EFF_QUALITY_ANTIALIASED 2 #define SC_EFF_QUALITY_LCD_OPTIMIZED 3 + +#define SCWIN_TECH_GDI 0 +#define SCWIN_TECH_DIRECTWRITE 0 diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index 6304d2e5e..54b455111 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -236,14 +236,21 @@ bool LoadD2D() { } struct FormatAndMetrics { + HFONT hfont; IDWriteTextFormat *pTextFormat; int extraFontFlag; FLOAT yAscent; FLOAT yDescent; FormatAndMetrics(IDWriteTextFormat *pTextFormat_, int extraFontFlag_, FLOAT yAscent_, FLOAT yDescent_) : - pTextFormat(pTextFormat_), extraFontFlag(extraFontFlag_), yAscent(yAscent_), yDescent(yDescent_) { + hfont(0), pTextFormat(pTextFormat_), extraFontFlag(extraFontFlag_), yAscent(yAscent_), yDescent(yDescent_) { + } + FormatAndMetrics(HFONT hfont_, int extraFontFlag_) : + hfont(hfont_), pTextFormat(0), extraFontFlag(extraFontFlag_), yAscent(2), yDescent(1) { } ~FormatAndMetrics() { + if (hfont) + ::DeleteObject(hfont); + if (pTextFormat) pTextFormat->Release(); pTextFormat = 0; extraFontFlag = 0; @@ -328,6 +335,7 @@ static int HashFont(const FontParameters &fp) { ((fp.extraFontFlag & SC_EFF_QUALITY_MASK) << 9) ^ ((fp.weight/100) << 12) ^ (fp.italic ? 0x20000000 : 0) ^ + (fp.technology << 15) ^ fp.faceName[0]; } @@ -336,6 +344,7 @@ class FontCached : Font { int usage; float size; LOGFONTA lf; + int technology; int hash; FontCached(const FontParameters &fp); ~FontCached() {} @@ -353,9 +362,13 @@ FontCached *FontCached::first = 0; FontCached::FontCached(const FontParameters &fp) : next(0), usage(0), size(1.0), hash(0) { SetLogFont(lf, fp.faceName, fp.characterSet, fp.size, fp.weight, fp.italic, fp.extraFontFlag); + technology = fp.technology; hash = HashFont(fp); fid = 0; - if (pIDWriteFactory) { + if (technology == SCWIN_TECH_GDI) { + HFONT hfont = ::CreateFontIndirectA(&lf); + fid = reinterpret_cast<void *>(new FormatAndMetrics(hfont, fp.extraFontFlag)); + } else { IDWriteTextFormat *pTextFormat; const int faceSize = 200; WCHAR wszFace[faceSize]; @@ -398,6 +411,7 @@ bool FontCached::SameAs(const FontParameters &fp) { (lf.lfItalic == static_cast<BYTE>(fp.italic ? 1 : 0)) && (lf.lfCharSet == fp.characterSet) && (lf.lfQuality == Win32MapFontQuality(fp.extraFontFlag)) && + (technology == fp.technology) && 0 == strcmp(lf.lfFaceName,fp.faceName); } @@ -469,11 +483,708 @@ void Font::Release() { fid = 0; } +// Buffer to hold strings and string position arrays without always allocating on heap. +// May sometimes have string too long to allocate on stack. So use a fixed stack-allocated buffer +// when less than safe size otherwise allocate on heap and free automatically. +template<typename T, int lengthStandard> +class VarBuffer { + T bufferStandard[lengthStandard]; +public: + T *buffer; + VarBuffer(size_t length) : buffer(0) { + if (length > lengthStandard) { + buffer = new T[length]; + } else { + buffer = bufferStandard; + } + } + ~VarBuffer() { + if (buffer != bufferStandard) { + delete []buffer; + buffer = 0; + } + } +}; + +const int stackBufferLength = 10000; +class TextWide : public VarBuffer<wchar_t, stackBufferLength> { +public: + int tlen; + TextWide(const char *s, int len, bool unicodeMode, int codePage=0) : + VarBuffer<wchar_t, stackBufferLength>(len) { + if (unicodeMode) { + tlen = UTF16FromUTF8(s, len, buffer, len); + } else { + // Support Asian string display in 9x English + tlen = ::MultiByteToWideChar(codePage, 0, s, len, buffer, len); + } + } +}; +typedef VarBuffer<XYPOSITION, stackBufferLength> TextPositions; + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +class SurfaceGDI : public Surface { + bool unicodeMode; + HDC hdc; + bool hdcOwned; + HPEN pen; + HPEN penOld; + HBRUSH brush; + HBRUSH brushOld; + HFONT font; + HFONT fontOld; + HBITMAP bitmap; + HBITMAP bitmapOld; + HPALETTE paletteOld; + int maxWidthMeasure; + int maxLenText; + + int codePage; + // If 9x OS and current code page is same as ANSI code page. + bool win9xACPSame; + + void BrushColor(ColourAllocated back); + void SetFont(Font &font_); + + // Private so SurfaceGDI objects can not be copied + SurfaceGDI(const SurfaceGDI &); + SurfaceGDI &operator=(const SurfaceGDI &); +public: + SurfaceGDI(); + virtual ~SurfaceGDI(); + + void Init(WindowID wid); + void Init(SurfaceID sid, WindowID wid); + void InitPixMap(int width, int height, Surface *surface_, WindowID wid); + + void Release(); + bool Initialised(); + void PenColour(ColourAllocated fore); + int LogPixelsY(); + int DeviceHeightFont(int points); + void MoveTo(int x_, int y_); + void LineTo(int x_, int y_); + void Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back); + void RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back); + void FillRectangle(PRectangle rc, ColourAllocated back); + void FillRectangle(PRectangle rc, Surface &surfacePattern); + void RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back); + void AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, + ColourAllocated outline, int alphaOutline, int flags); + void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage); + void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back); + void Copy(PRectangle rc, Point from, Surface &surfaceSource); + + void DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT fuOptions); + void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); + void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); + void DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore); + void MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions); + XYPOSITION WidthText(Font &font_, const char *s, int len); + XYPOSITION WidthChar(Font &font_, char ch); + XYPOSITION Ascent(Font &font_); + XYPOSITION Descent(Font &font_); + XYPOSITION InternalLeading(Font &font_); + XYPOSITION ExternalLeading(Font &font_); + XYPOSITION Height(Font &font_); + XYPOSITION AverageCharWidth(Font &font_); + + int SetPalette(Palette *pal, bool inBackGround); + void SetClip(PRectangle rc); + void FlushCachedState(); + + void SetUnicodeMode(bool unicodeMode_); + void SetDBCSMode(int codePage_); +}; + +#ifdef SCI_NAMESPACE +} //namespace Scintilla +#endif + +SurfaceGDI::SurfaceGDI() : + unicodeMode(false), + hdc(0), hdcOwned(false), + pen(0), penOld(0), + brush(0), brushOld(0), + font(0), fontOld(0), + bitmap(0), bitmapOld(0), + paletteOld(0) { + // Windows 9x has only a 16 bit coordinate system so break after 30000 pixels + maxWidthMeasure = IsNT() ? INT_MAX : 30000; + // There appears to be a 16 bit string length limit in GDI on NT and a limit of + // 8192 characters on Windows 95. + maxLenText = IsNT() ? 65535 : 8192; + + codePage = 0; + win9xACPSame = false; +} + +SurfaceGDI::~SurfaceGDI() { + Release(); +} + +void SurfaceGDI::Release() { + if (penOld) { + ::SelectObject(reinterpret_cast<HDC>(hdc), penOld); + ::DeleteObject(pen); + penOld = 0; + } + pen = 0; + if (brushOld) { + ::SelectObject(reinterpret_cast<HDC>(hdc), brushOld); + ::DeleteObject(brush); + brushOld = 0; + } + brush = 0; + if (fontOld) { + // Fonts are not deleted as they are owned by a Font object + ::SelectObject(reinterpret_cast<HDC>(hdc), fontOld); + fontOld = 0; + } + font = 0; + if (bitmapOld) { + ::SelectObject(reinterpret_cast<HDC>(hdc), bitmapOld); + ::DeleteObject(bitmap); + bitmapOld = 0; + } + bitmap = 0; + if (paletteOld) { + // Palettes are not deleted as they are owned by a Palette object + ::SelectPalette(reinterpret_cast<HDC>(hdc), + reinterpret_cast<HPALETTE>(paletteOld), TRUE); + paletteOld = 0; + } + if (hdcOwned) { + ::DeleteDC(reinterpret_cast<HDC>(hdc)); + hdc = 0; + hdcOwned = false; + } +} + +bool SurfaceGDI::Initialised() { + return hdc != 0; +} + +void SurfaceGDI::Init(WindowID) { + Release(); + hdc = ::CreateCompatibleDC(NULL); + hdcOwned = true; + ::SetTextAlign(reinterpret_cast<HDC>(hdc), TA_BASELINE); +} + +void SurfaceGDI::Init(SurfaceID sid, WindowID) { + Release(); + hdc = reinterpret_cast<HDC>(sid); + ::SetTextAlign(reinterpret_cast<HDC>(hdc), TA_BASELINE); +} + +void SurfaceGDI::InitPixMap(int width, int height, Surface *surface_, WindowID) { + Release(); + hdc = ::CreateCompatibleDC(static_cast<SurfaceGDI *>(surface_)->hdc); + hdcOwned = true; + bitmap = ::CreateCompatibleBitmap(static_cast<SurfaceGDI *>(surface_)->hdc, width, height); + bitmapOld = static_cast<HBITMAP>(::SelectObject(hdc, bitmap)); + ::SetTextAlign(reinterpret_cast<HDC>(hdc), TA_BASELINE); +} + +void SurfaceGDI::PenColour(ColourAllocated fore) { + if (pen) { + ::SelectObject(hdc, penOld); + ::DeleteObject(pen); + pen = 0; + penOld = 0; + } + pen = ::CreatePen(0,1,fore.AsLong()); + penOld = static_cast<HPEN>(::SelectObject(reinterpret_cast<HDC>(hdc), pen)); +} + +void SurfaceGDI::BrushColor(ColourAllocated back) { + if (brush) { + ::SelectObject(hdc, brushOld); + ::DeleteObject(brush); + brush = 0; + brushOld = 0; + } + // Only ever want pure, non-dithered brushes + ColourAllocated colourNearest = ::GetNearestColor(hdc, back.AsLong()); + brush = ::CreateSolidBrush(colourNearest.AsLong()); + brushOld = static_cast<HBRUSH>(::SelectObject(hdc, brush)); +} + +void SurfaceGDI::SetFont(Font &font_) { + if (font_.GetID() != font) { + FormatAndMetrics *pfm = reinterpret_cast<FormatAndMetrics *>(font_.GetID()); + if (fontOld) { + ::SelectObject(hdc, pfm->hfont); + } else { + fontOld = static_cast<HFONT>(::SelectObject(hdc, pfm->hfont)); + } + font = reinterpret_cast<HFONT>(pfm->hfont); + } +} + +int SurfaceGDI::LogPixelsY() { + return ::GetDeviceCaps(hdc, LOGPIXELSY); +} + +int SurfaceGDI::DeviceHeightFont(int points) { + return ::MulDiv(points, LogPixelsY(), 72); +} + +void SurfaceGDI::MoveTo(int x_, int y_) { + ::MoveToEx(hdc, x_, y_, 0); +} + +void SurfaceGDI::LineTo(int x_, int y_) { + ::LineTo(hdc, x_, y_); +} + +void SurfaceGDI::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) { + PenColour(fore); + BrushColor(back); + ::Polygon(hdc, reinterpret_cast<POINT *>(pts), npts); +} + +void SurfaceGDI::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) { + PenColour(fore); + BrushColor(back); + ::Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom); +} + +void SurfaceGDI::FillRectangle(PRectangle rc, ColourAllocated back) { + // Using ExtTextOut rather than a FillRect ensures that no dithering occurs. + // There is no need to allocate a brush either. + RECT rcw = RectFromPRectangle(rc); + ::SetBkColor(hdc, back.AsLong()); + ::ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE, &rcw, TEXT(""), 0, NULL); +} + +void SurfaceGDI::FillRectangle(PRectangle rc, Surface &surfacePattern) { + HBRUSH br; + if (static_cast<SurfaceGDI &>(surfacePattern).bitmap) + br = ::CreatePatternBrush(static_cast<SurfaceGDI &>(surfacePattern).bitmap); + else // Something is wrong so display in red + br = ::CreateSolidBrush(RGB(0xff, 0, 0)); + RECT rcw = RectFromPRectangle(rc); + ::FillRect(hdc, &rcw, br); + ::DeleteObject(br); +} + +void SurfaceGDI::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) { + PenColour(fore); + BrushColor(back); + ::RoundRect(hdc, + rc.left + 1, rc.top, + rc.right - 1, rc.bottom, + 8, 8); +} + +// Plot a point into a DWORD buffer symetrically to all 4 qudrants +static void AllFour(DWORD *pixels, int width, int height, int x, int y, DWORD val) { + pixels[y*width+x] = val; + pixels[y*width+width-1-x] = val; + pixels[(height-1-y)*width+x] = val; + pixels[(height-1-y)*width+width-1-x] = val; +} + +#ifndef AC_SRC_OVER +#define AC_SRC_OVER 0x00 +#endif +#ifndef AC_SRC_ALPHA +#define AC_SRC_ALPHA 0x01 +#endif + +static DWORD dwordFromBGRA(byte b, byte g, byte r, byte a) { + union { + byte pixVal[4]; + DWORD val; + } converter; + converter.pixVal[0] = b; + converter.pixVal[1] = g; + converter.pixVal[2] = r; + converter.pixVal[3] = a; + return converter.val; +} + +void SurfaceGDI::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, + ColourAllocated outline, int alphaOutline, int /* flags*/ ) { + if (AlphaBlendFn && rc.Width() > 0) { + HDC hMemDC = ::CreateCompatibleDC(reinterpret_cast<HDC>(hdc)); + int width = rc.Width(); + int height = rc.Height(); + // Ensure not distorted too much by corners when small + cornerSize = Platform::Minimum(cornerSize, (Platform::Minimum(width, height) / 2) - 2); + BITMAPINFO bpih = {sizeof(BITMAPINFOHEADER), width, height, 1, 32, BI_RGB, 0, 0, 0, 0, 0}; + void *image = 0; + HBITMAP hbmMem = CreateDIBSection(reinterpret_cast<HDC>(hMemDC), &bpih, + DIB_RGB_COLORS, &image, NULL, 0); + + HBITMAP hbmOld = SelectBitmap(hMemDC, hbmMem); + + DWORD valEmpty = dwordFromBGRA(0,0,0,0); + DWORD valFill = dwordFromBGRA( + static_cast<byte>(GetBValue(fill.AsLong()) * alphaFill / 255), + static_cast<byte>(GetGValue(fill.AsLong()) * alphaFill / 255), + static_cast<byte>(GetRValue(fill.AsLong()) * alphaFill / 255), + static_cast<byte>(alphaFill)); + DWORD valOutline = dwordFromBGRA( + static_cast<byte>(GetBValue(outline.AsLong()) * alphaOutline / 255), + static_cast<byte>(GetGValue(outline.AsLong()) * alphaOutline / 255), + static_cast<byte>(GetRValue(outline.AsLong()) * alphaOutline / 255), + static_cast<byte>(alphaOutline)); + DWORD *pixels = reinterpret_cast<DWORD *>(image); + for (int y=0; y<height; y++) { + for (int x=0; x<width; x++) { + if ((x==0) || (x==width-1) || (y == 0) || (y == height-1)) { + pixels[y*width+x] = valOutline; + } else { + pixels[y*width+x] = valFill; + } + } + } + for (int c=0;c<cornerSize; c++) { + for (int x=0;x<c+1; x++) { + AllFour(pixels, width, height, x, c-x, valEmpty); + } + } + for (int x=1;x<cornerSize; x++) { + AllFour(pixels, width, height, x, cornerSize-x, valOutline); + } + + BLENDFUNCTION merge = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; + + AlphaBlendFn(reinterpret_cast<HDC>(hdc), rc.left, rc.top, width, height, hMemDC, 0, 0, width, height, merge); + + SelectBitmap(hMemDC, hbmOld); + ::DeleteObject(hbmMem); + ::DeleteDC(hMemDC); + } else { + BrushColor(outline); + RECT rcw = RectFromPRectangle(rc); + FrameRect(hdc, &rcw, brush); + } +} + +void SurfaceGDI::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) { + if (AlphaBlendFn && rc.Width() > 0) { + HDC hMemDC = ::CreateCompatibleDC(reinterpret_cast<HDC>(hdc)); + if (rc.Width() > width) + rc.left += (rc.Width() - width) / 2; + rc.right = rc.left + width; + if (rc.Height() > height) + rc.top += (rc.Height() - height) / 2; + rc.bottom = rc.top + height; + + BITMAPINFO bpih = {sizeof(BITMAPINFOHEADER), width, height, 1, 32, BI_RGB, 0, 0, 0, 0, 0}; + unsigned char *image = 0; + HBITMAP hbmMem = CreateDIBSection(reinterpret_cast<HDC>(hMemDC), &bpih, + DIB_RGB_COLORS, reinterpret_cast<void **>(&image), NULL, 0); + HBITMAP hbmOld = SelectBitmap(hMemDC, hbmMem); + + for (int y=height-1; y>=0; y--) { + for (int x=0; x<width; x++) { + unsigned char *pixel = image + (y*width+x) * 4; + unsigned char alpha = pixelsImage[3]; + // Input is RGBA, output is BGRA with premultiplied alpha + pixel[2] = (*pixelsImage++) * alpha / 255; + pixel[1] = (*pixelsImage++) * alpha / 255; + pixel[0] = (*pixelsImage++) * alpha / 255; + pixel[3] = *pixelsImage++; + } + } + + BLENDFUNCTION merge = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; + + AlphaBlendFn(reinterpret_cast<HDC>(hdc), rc.left, rc.top, rc.Width(), rc.Height(), hMemDC, 0, 0, width, height, merge); + + SelectBitmap(hMemDC, hbmOld); + ::DeleteObject(hbmMem); + ::DeleteDC(hMemDC); + + } +} + +void SurfaceGDI::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) { + PenColour(fore); + BrushColor(back); + ::Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom); +} + +void SurfaceGDI::Copy(PRectangle rc, Point from, Surface &surfaceSource) { + ::BitBlt(hdc, + rc.left, rc.top, rc.Width(), rc.Height(), + static_cast<SurfaceGDI &>(surfaceSource).hdc, from.x, from.y, SRCCOPY); +} + +typedef VarBuffer<int, stackBufferLength> TextPositionsI; + +void SurfaceGDI::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT fuOptions) { + SetFont(font_); + RECT rcw = RectFromPRectangle(rc); + SIZE sz={0,0}; + int pos = 0; + int x = rc.left; + + // Text drawing may fail if the text is too big. + // If it does fail, slice up into segments and draw each segment. + const int maxSegmentLength = 0x200; + + if ((!unicodeMode) && (IsNT() || (codePage==0) || win9xACPSame)) { + // Use ANSI calls + int lenDraw = Platform::Minimum(len, maxLenText); + if (!::ExtTextOutA(hdc, x, ybase, fuOptions, &rcw, s, lenDraw, NULL)) { + while (lenDraw > pos) { + int seglen = Platform::Minimum(maxSegmentLength, lenDraw - pos); + if (!::ExtTextOutA(hdc, x, ybase, fuOptions, &rcw, s+pos, seglen, NULL)) { + PLATFORM_ASSERT(false); + return; + } + ::GetTextExtentPoint32A(hdc, s+pos, seglen, &sz); + x += sz.cx; + pos += seglen; + } + } + } else { + // Use Unicode calls + const TextWide tbuf(s, len, unicodeMode, codePage); + if (!::ExtTextOutW(hdc, x, ybase, fuOptions, &rcw, tbuf.buffer, tbuf.tlen, NULL)) { + while (tbuf.tlen > pos) { + int seglen = Platform::Minimum(maxSegmentLength, tbuf.tlen - pos); + if (!::ExtTextOutW(hdc, x, ybase, fuOptions, &rcw, tbuf.buffer+pos, seglen, NULL)) { + PLATFORM_ASSERT(false); + return; + } + ::GetTextExtentPoint32W(hdc, tbuf.buffer+pos, seglen, &sz); + x += sz.cx; + pos += seglen; + } + } + } +} + +void SurfaceGDI::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, + ColourAllocated fore, ColourAllocated back) { + ::SetTextColor(hdc, fore.AsLong()); + ::SetBkColor(hdc, back.AsLong()); + DrawTextCommon(rc, font_, ybase, s, len, ETO_OPAQUE); +} + +void SurfaceGDI::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, + ColourAllocated fore, ColourAllocated back) { + ::SetTextColor(hdc, fore.AsLong()); + ::SetBkColor(hdc, back.AsLong()); + DrawTextCommon(rc, font_, ybase, s, len, ETO_OPAQUE | ETO_CLIPPED); +} + +void SurfaceGDI::DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, + ColourAllocated fore) { + // Avoid drawing spaces in transparent mode + for (int i=0;i<len;i++) { + if (s[i] != ' ') { + ::SetTextColor(hdc, fore.AsLong()); + ::SetBkMode(hdc, TRANSPARENT); + DrawTextCommon(rc, font_, ybase, s, len, 0); + ::SetBkMode(hdc, OPAQUE); + return; + } + } +} + +XYPOSITION SurfaceGDI::WidthText(Font &font_, const char *s, int len) { + SetFont(font_); + SIZE sz={0,0}; + if ((!unicodeMode) && (IsNT() || (codePage==0) || win9xACPSame)) { + ::GetTextExtentPoint32A(hdc, s, Platform::Minimum(len, maxLenText), &sz); + } else { + const TextWide tbuf(s, len, unicodeMode, codePage); + ::GetTextExtentPoint32W(hdc, tbuf.buffer, tbuf.tlen, &sz); + } + return sz.cx; +} + +void SurfaceGDI::MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions) { + SetFont(font_); + SIZE sz={0,0}; + int fit = 0; + if (unicodeMode) { + const TextWide tbuf(s, len, unicodeMode, codePage); + TextPositionsI poses(tbuf.tlen); + fit = tbuf.tlen; + if (!::GetTextExtentExPointW(hdc, tbuf.buffer, tbuf.tlen, maxWidthMeasure, &fit, poses.buffer, &sz)) { + // Likely to have failed because on Windows 9x where function not available + // So measure the character widths by measuring each initial substring + // Turns a linear operation into a qudratic but seems fast enough on test files + for (int widthSS=0; widthSS < tbuf.tlen; widthSS++) { + ::GetTextExtentPoint32W(hdc, tbuf.buffer, widthSS+1, &sz); + poses.buffer[widthSS] = sz.cx; + } + } + // Map the widths given for UTF-16 characters back onto the UTF-8 input string + int ui=0; + const unsigned char *us = reinterpret_cast<const unsigned char *>(s); + int i=0; + while (ui<fit) { + unsigned char uch = us[i]; + unsigned int lenChar = 1; + if (uch >= (0x80 + 0x40 + 0x20 + 0x10)) { + lenChar = 4; + ui++; + } else if (uch >= (0x80 + 0x40 + 0x20)) { + lenChar = 3; + } else if (uch >= (0x80)) { + lenChar = 2; + } + for (unsigned int bytePos=0; (bytePos<lenChar) && (i<len); bytePos++) { + positions[i++] = poses.buffer[ui]; + } + ui++; + } + int lastPos = 0; + if (i > 0) + lastPos = positions[i-1]; + while (i<len) { + positions[i++] = lastPos; + } + } else if (IsNT() || (codePage==0) || win9xACPSame) { + // Zero positions to avoid random behaviour on failure. + memset(positions, 0, len * sizeof(*positions)); + // len may be larger than platform supports so loop over segments small enough for platform + int startOffset = 0; + while (len > 0) { + int lenBlock = Platform::Minimum(len, maxLenText); + TextPositionsI poses(len); + if (!::GetTextExtentExPointA(hdc, s, lenBlock, maxWidthMeasure, &fit, poses.buffer, &sz)) { + // Eeek - a NULL DC or other foolishness could cause this. + return; + } else if (fit < lenBlock) { + // For some reason, such as an incomplete DBCS character + // Not all the positions are filled in so make them equal to end. + for (int i = fit;i<lenBlock;i++) + poses.buffer[i] = poses.buffer[fit-1]; + } + for (int i=0;i<lenBlock;i++) + positions[i] = poses.buffer[i] + startOffset; + startOffset = poses.buffer[lenBlock-1]; + len -= lenBlock; + positions += lenBlock; + s += lenBlock; + } + } else { + // Support Asian string display in 9x English + const TextWide tbuf(s, len, unicodeMode, codePage); + TextPositionsI poses(tbuf.tlen); + for (int widthSS=0; widthSS<tbuf.tlen; widthSS++) { + ::GetTextExtentPoint32W(hdc, tbuf.buffer, widthSS+1, &sz); + poses.buffer[widthSS] = sz.cx; + } + + int ui = 0; + for (int i=0;i<len;) { + if (::IsDBCSLeadByteEx(codePage, s[i])) { + positions[i] = poses.buffer[ui]; + positions[i+1] = poses.buffer[ui]; + i += 2; + } else { + positions[i] = poses.buffer[ui]; + i++; + } + + ui++; + } + } +} + +XYPOSITION SurfaceGDI::WidthChar(Font &font_, char ch) { + SetFont(font_); + SIZE sz; + ::GetTextExtentPoint32A(hdc, &ch, 1, &sz); + return sz.cx; +} + +XYPOSITION SurfaceGDI::Ascent(Font &font_) { + SetFont(font_); + TEXTMETRIC tm; + ::GetTextMetrics(hdc, &tm); + return tm.tmAscent; +} + +XYPOSITION SurfaceGDI::Descent(Font &font_) { + SetFont(font_); + TEXTMETRIC tm; + ::GetTextMetrics(hdc, &tm); + return tm.tmDescent; +} + +XYPOSITION SurfaceGDI::InternalLeading(Font &font_) { + SetFont(font_); + TEXTMETRIC tm; + ::GetTextMetrics(hdc, &tm); + return tm.tmInternalLeading; +} + +XYPOSITION SurfaceGDI::ExternalLeading(Font &font_) { + SetFont(font_); + TEXTMETRIC tm; + ::GetTextMetrics(hdc, &tm); + return tm.tmExternalLeading; +} + +XYPOSITION SurfaceGDI::Height(Font &font_) { + SetFont(font_); + TEXTMETRIC tm; + ::GetTextMetrics(hdc, &tm); + return tm.tmHeight; +} + +XYPOSITION SurfaceGDI::AverageCharWidth(Font &font_) { + SetFont(font_); + TEXTMETRIC tm; + ::GetTextMetrics(hdc, &tm); + return tm.tmAveCharWidth; +} + +int SurfaceGDI::SetPalette(Palette *pal, bool inBackGround) { + if (paletteOld) { + ::SelectPalette(hdc, paletteOld, TRUE); + } + paletteOld = 0; + int changes = 0; + if (pal->allowRealization) { + paletteOld = ::SelectPalette(hdc, + reinterpret_cast<HPALETTE>(pal->hpal), inBackGround); + changes = ::RealizePalette(hdc); + } + return changes; +} + +void SurfaceGDI::SetClip(PRectangle rc) { + ::IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom); +} + +void SurfaceGDI::FlushCachedState() { + pen = 0; + brush = 0; + font = 0; +} + +void SurfaceGDI::SetUnicodeMode(bool unicodeMode_) { + unicodeMode=unicodeMode_; +} + +void SurfaceGDI::SetDBCSMode(int codePage_) { + // No action on window as automatically handled by system. + codePage = codePage_; + win9xACPSame = !IsNT() && ((unsigned int)codePage == ::GetACP()); +} + #ifdef SCI_NAMESPACE namespace Scintilla { #endif -class SurfaceImpl : public Surface { +class SurfaceD2D : public Surface { bool unicodeMode; HDC hdc; bool hdcOwned; @@ -500,12 +1211,12 @@ class SurfaceImpl : public Surface { void SetFont(Font &font_); - // Private so SurfaceImpl objects can not be copied - SurfaceImpl(const SurfaceImpl &); - SurfaceImpl &operator=(const SurfaceImpl &); + // Private so SurfaceD2D objects can not be copied + SurfaceD2D(const SurfaceD2D &); + SurfaceD2D &operator=(const SurfaceD2D &); public: - SurfaceImpl(); - virtual ~SurfaceImpl(); + SurfaceD2D(); + virtual ~SurfaceD2D(); void SetDWrite(HDC hdc); void Init(WindowID wid); @@ -560,7 +1271,7 @@ public: } //namespace Scintilla #endif -SurfaceImpl::SurfaceImpl() : +SurfaceD2D::SurfaceD2D() : unicodeMode(false), hdc(0), hdcOwned(false), x(0), y(0) { @@ -585,11 +1296,11 @@ SurfaceImpl::SurfaceImpl() : hasBegun = false; } -SurfaceImpl::~SurfaceImpl() { +SurfaceD2D::~SurfaceD2D() { Release(); } -void SurfaceImpl::Release() { +void SurfaceD2D::Release() { if (hdcOwned) { ::DeleteDC(reinterpret_cast<HDC>(hdc)); hdc = 0; @@ -612,20 +1323,20 @@ void SurfaceImpl::Release() { } } -void SurfaceImpl::SetDWrite(HDC hdc) { +void SurfaceD2D::SetDWrite(HDC hdc) { dpiScaleX = GetDeviceCaps(hdc, LOGPIXELSX) / 96.0f; dpiScaleY = GetDeviceCaps(hdc, LOGPIXELSY) / 96.0f; } -bool SurfaceImpl::Initialised() { +bool SurfaceD2D::Initialised() { return pRenderTarget != 0; } -HRESULT SurfaceImpl::FlushDrawing() { +HRESULT SurfaceD2D::FlushDrawing() { return pRenderTarget->Flush(); } -void SurfaceImpl::Init(WindowID wid) { +void SurfaceD2D::Init(WindowID wid) { Release(); hdc = ::CreateCompatibleDC(NULL); hdcOwned = true; @@ -635,7 +1346,7 @@ void SurfaceImpl::Init(WindowID wid) { SetDWrite(hdc); } -void SurfaceImpl::Init(SurfaceID sid, WindowID) { +void SurfaceD2D::Init(SurfaceID sid, WindowID) { Release(); hdc = ::CreateCompatibleDC(NULL); hdcOwned = true; @@ -644,11 +1355,11 @@ void SurfaceImpl::Init(SurfaceID sid, WindowID) { SetDWrite(hdc); } -void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID) { +void SurfaceD2D::InitPixMap(int width, int height, Surface *surface_, WindowID) { Release(); hdc = ::CreateCompatibleDC(NULL); // Just for measurement hdcOwned = true; - SurfaceImpl *psurfOther = static_cast<SurfaceImpl *>(surface_); + SurfaceD2D *psurfOther = static_cast<SurfaceD2D *>(surface_); ID2D1BitmapRenderTarget *pCompatibleRenderTarget = NULL; HRESULT hr = psurfOther->pRenderTarget->CreateCompatibleRenderTarget( D2D1::SizeF(width, height), &pCompatibleRenderTarget); @@ -659,11 +1370,11 @@ void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID) } } -void SurfaceImpl::PenColour(ColourAllocated fore) { +void SurfaceD2D::PenColour(ColourAllocated fore) { D2DPenColour(fore); } -void SurfaceImpl::D2DPenColour(ColourAllocated fore, int alpha) { +void SurfaceD2D::D2DPenColour(ColourAllocated fore, int alpha) { if (pRenderTarget) { D2D_COLOR_F col; col.r = (fore.AsLong() & 0xff) / 255.0; @@ -682,25 +1393,25 @@ void SurfaceImpl::D2DPenColour(ColourAllocated fore, int alpha) { } } -void SurfaceImpl::SetFont(Font &font_) { - FormatAndMetrics *pfabl = reinterpret_cast<FormatAndMetrics *>(font_.GetID()); - pTextFormat = pfabl->pTextFormat; - yAscent = pfabl->yAscent; - yDescent = pfabl->yDescent; +void SurfaceD2D::SetFont(Font &font_) { + FormatAndMetrics *pfm = reinterpret_cast<FormatAndMetrics *>(font_.GetID()); + pTextFormat = pfm->pTextFormat; + yAscent = pfm->yAscent; + yDescent = pfm->yDescent; if (pRenderTarget) { - pRenderTarget->SetTextAntialiasMode(DWriteMapFontQuality(pfabl->extraFontFlag)); + pRenderTarget->SetTextAntialiasMode(DWriteMapFontQuality(pfm->extraFontFlag)); } } -int SurfaceImpl::LogPixelsY() { +int SurfaceD2D::LogPixelsY() { return ::GetDeviceCaps(hdc, LOGPIXELSY); } -int SurfaceImpl::DeviceHeightFont(int points) { +int SurfaceD2D::DeviceHeightFont(int points) { return ::MulDiv(points, LogPixelsY(), 72); } -void SurfaceImpl::MoveTo(int x_, int y_) { +void SurfaceD2D::MoveTo(int x_, int y_) { x = x_; y = y_; } @@ -718,7 +1429,7 @@ static int RoundFloat(float f) { return int(f+0.5); } -void SurfaceImpl::LineTo(int x_, int y_) { +void SurfaceD2D::LineTo(int x_, int y_) { if (pRenderTarget) { int xDiff = x_ - x; int xDelta = Delta(xDiff); @@ -748,7 +1459,7 @@ void SurfaceImpl::LineTo(int x_, int y_) { } } -void SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) { +void SurfaceD2D::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) { if (pRenderTarget) { ID2D1Factory *pFactory = 0; pRenderTarget->GetFactory(&pFactory); @@ -777,7 +1488,7 @@ void SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllo } } -void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) { +void SurfaceD2D::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) { if (pRenderTarget) { D2DPenColour(back); D2D1_RECT_F rectangle1 = D2D1::RectF(RoundFloat(rc.left) + 0.5, rc.top+0.5, RoundFloat(rc.right) - 0.5, rc.bottom-0.5); @@ -788,7 +1499,7 @@ void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAlloc } } -void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) { +void SurfaceD2D::FillRectangle(PRectangle rc, ColourAllocated back) { if (pRenderTarget) { D2DPenColour(back); D2D1_RECT_F rectangle1 = D2D1::RectF(RoundFloat(rc.left), rc.top, RoundFloat(rc.right), rc.bottom); @@ -796,8 +1507,8 @@ void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) { } } -void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) { - SurfaceImpl &surfOther = static_cast<SurfaceImpl &>(surfacePattern); +void SurfaceD2D::FillRectangle(PRectangle rc, Surface &surfacePattern) { + SurfaceD2D &surfOther = static_cast<SurfaceD2D &>(surfacePattern); surfOther.FlushDrawing(); ID2D1Bitmap *pBitmap = NULL; ID2D1BitmapRenderTarget *pCompatibleRenderTarget = reinterpret_cast<ID2D1BitmapRenderTarget *>( @@ -820,7 +1531,7 @@ void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) { } } -void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) { +void SurfaceD2D::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) { if (pRenderTarget) { D2D1_ROUNDED_RECT roundedRectFill = D2D1::RoundedRect( D2D1::RectF(rc.left+1.0, rc.top+1.0, rc.right-1.0, rc.bottom-1.0), @@ -836,7 +1547,7 @@ void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAl } } -void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, +void SurfaceD2D::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, ColourAllocated outline, int alphaOutline, int /* flags*/ ) { if (pRenderTarget) { D2D1_ROUNDED_RECT roundedRectFill = D2D1::RoundedRect( @@ -853,7 +1564,7 @@ void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated } } -void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) { +void SurfaceD2D::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) { if (pRenderTarget) { if (rc.Width() > width) rc.left += (rc.Width() - width) / 2; @@ -889,7 +1600,7 @@ void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsi } } -void SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) { +void SurfaceD2D::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) { if (pRenderTarget) { FLOAT radius = rc.Width() / 2.0f - 1.0f; D2D1_ELLIPSE ellipse = D2D1::Ellipse( @@ -903,8 +1614,8 @@ void SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated b } } -void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) { - SurfaceImpl &surfOther = static_cast<SurfaceImpl &>(surfaceSource); +void SurfaceD2D::Copy(PRectangle rc, Point from, Surface &surfaceSource) { + SurfaceD2D &surfOther = static_cast<SurfaceD2D &>(surfaceSource); surfOther.FlushDrawing(); ID2D1BitmapRenderTarget *pCompatibleRenderTarget = reinterpret_cast<ID2D1BitmapRenderTarget *>( surfOther.pRenderTarget); @@ -920,46 +1631,7 @@ void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) { } } -// Buffer to hold strings and string position arrays without always allocating on heap. -// May sometimes have string too long to allocate on stack. So use a fixed stack-allocated buffer -// when less than safe size otherwise allocate on heap and free automatically. -template<typename T, int lengthStandard> -class VarBuffer { - T bufferStandard[lengthStandard]; -public: - T *buffer; - VarBuffer(size_t length) : buffer(0) { - if (length > lengthStandard) { - buffer = new T[length]; - } else { - buffer = bufferStandard; - } - } - ~VarBuffer() { - if (buffer != bufferStandard) { - delete []buffer; - buffer = 0; - } - } -}; - -const int stackBufferLength = 10000; -class TextWide : public VarBuffer<wchar_t, stackBufferLength> { -public: - int tlen; - TextWide(const char *s, int len, bool unicodeMode, int codePage=0) : - VarBuffer<wchar_t, stackBufferLength>(len) { - if (unicodeMode) { - tlen = UTF16FromUTF8(s, len, buffer, len); - } else { - // Support Asian string display in 9x English - tlen = ::MultiByteToWideChar(codePage, 0, s, len, buffer, len); - } - } -}; -typedef VarBuffer<XYPOSITION, stackBufferLength> TextPositions; - -void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT) { +void SurfaceD2D::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT) { SetFont(font_); RECT rcw = RectFromPRectangle(rc); @@ -985,7 +1657,7 @@ void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, c } } -void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, +void SurfaceD2D::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back) { if (pRenderTarget) { FillRectangle(rc, back); @@ -994,7 +1666,7 @@ void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, c } } -void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, +void SurfaceD2D::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back) { if (pRenderTarget) { FillRectangle(rc, back); @@ -1003,7 +1675,7 @@ void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, } } -void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, +void SurfaceD2D::DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore) { // Avoid drawing spaces in transparent mode for (int i=0;i<len;i++) { @@ -1017,7 +1689,7 @@ void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION yba } } -XYPOSITION SurfaceImpl::WidthText(Font &font_, const char *s, int len) { +XYPOSITION SurfaceD2D::WidthText(Font &font_, const char *s, int len) { FLOAT width = 1.0; SetFont(font_); const TextWide tbuf(s, len, unicodeMode, codePage); @@ -1035,7 +1707,7 @@ XYPOSITION SurfaceImpl::WidthText(Font &font_, const char *s, int len) { return int(width + 0.5); } -void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions) { +void SurfaceD2D::MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions) { SetFont(font_); int fit = 0; const TextWide tbuf(s, len, unicodeMode, codePage); @@ -1119,7 +1791,7 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, XYPOSITION } } -XYPOSITION SurfaceImpl::WidthChar(Font &font_, char ch) { +XYPOSITION SurfaceD2D::WidthChar(Font &font_, char ch) { FLOAT width = 1.0; SetFont(font_); if (pIDWriteFactory && pTextFormat) { @@ -1137,29 +1809,29 @@ XYPOSITION SurfaceImpl::WidthChar(Font &font_, char ch) { return int(width + 0.5); } -XYPOSITION SurfaceImpl::Ascent(Font &font_) { +XYPOSITION SurfaceD2D::Ascent(Font &font_) { SetFont(font_); return ceil(yAscent); } -XYPOSITION SurfaceImpl::Descent(Font &font_) { +XYPOSITION SurfaceD2D::Descent(Font &font_) { SetFont(font_); return ceil(yDescent); } -XYPOSITION SurfaceImpl::InternalLeading(Font &) { +XYPOSITION SurfaceD2D::InternalLeading(Font &) { return 0; } -XYPOSITION SurfaceImpl::ExternalLeading(Font &) { +XYPOSITION SurfaceD2D::ExternalLeading(Font &) { return 1; } -XYPOSITION SurfaceImpl::Height(Font &font_) { +XYPOSITION SurfaceD2D::Height(Font &font_) { return Ascent(font_) + Descent(font_); } -XYPOSITION SurfaceImpl::AverageCharWidth(Font &font_) { +XYPOSITION SurfaceD2D::AverageCharWidth(Font &font_) { FLOAT width = 1.0; SetFont(font_); if (pIDWriteFactory && pTextFormat) { @@ -1177,11 +1849,11 @@ XYPOSITION SurfaceImpl::AverageCharWidth(Font &font_) { return int(width + 0.5); } -int SurfaceImpl::SetPalette(Palette *, bool) { +int SurfaceD2D::SetPalette(Palette *, bool) { return 0; } -void SurfaceImpl::SetClip(PRectangle rc) { +void SurfaceD2D::SetClip(PRectangle rc) { if (pRenderTarget) { D2D1_RECT_F rcClip = {rc.left, rc.top, rc.right, rc.bottom}; pRenderTarget->PushAxisAlignedClip(rcClip, D2D1_ANTIALIAS_MODE_ALIASED); @@ -1189,21 +1861,24 @@ void SurfaceImpl::SetClip(PRectangle rc) { } } -void SurfaceImpl::FlushCachedState() { +void SurfaceD2D::FlushCachedState() { } -void SurfaceImpl::SetUnicodeMode(bool unicodeMode_) { +void SurfaceD2D::SetUnicodeMode(bool unicodeMode_) { unicodeMode=unicodeMode_; } -void SurfaceImpl::SetDBCSMode(int codePage_) { +void SurfaceD2D::SetDBCSMode(int codePage_) { // No action on window as automatically handled by system. codePage = codePage_; win9xACPSame = !IsNT() && ((unsigned int)codePage == ::GetACP()); } -Surface *Surface::Allocate(int /* technology */) { - return new SurfaceImpl; +Surface *Surface::Allocate(int technology) { + if (technology == SCWIN_TECH_GDI) + return new SurfaceGDI; + else + return new SurfaceD2D; } Window::~Window() { diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index b3b9d1bb0..525621b2c 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -383,8 +383,6 @@ void ScintillaWin::Initialise() { ::GetProcAddress(commctrl32, "_TrackMouseEvent"); } } - - LoadD2D(); } void ScintillaWin::Finalise() { @@ -546,25 +544,35 @@ LRESULT ScintillaWin::WndPaint(uptr_t wParam) { pps = &ps; ::BeginPaint(MainHWND(), pps); } - //AutoSurface surfaceWindow(pps->hdc, this); - EnsureRenderTarget(); - AutoSurface surfaceWindow(pRenderTarget, this); - if (surfaceWindow) { - pRenderTarget->BeginDraw(); - rcPaint = PRectangle(pps->rcPaint.left, pps->rcPaint.top, pps->rcPaint.right, pps->rcPaint.bottom); - PRectangle rcClient = GetClientRectangle(); - paintingAllText = rcPaint.Contains(rcClient); - if (paintingAllText) { - //Platform::DebugPrintf("Performing full text paint\n"); - } else { - //Platform::DebugPrintf("Performing partial paint %d .. %d\n", rcPaint.top, rcPaint.bottom); + if (technology == SC_TECHNOLOGY_DEFAULT) { + AutoSurface surfaceWindow(pps->hdc, this); + if (surfaceWindow) { + rcPaint = PRectangle(pps->rcPaint.left, pps->rcPaint.top, pps->rcPaint.right, pps->rcPaint.bottom); + PRectangle rcClient = GetClientRectangle(); + paintingAllText = rcPaint.Contains(rcClient); + Paint(surfaceWindow, rcPaint); + surfaceWindow->Release(); + } + } else { + EnsureRenderTarget(); + AutoSurface surfaceWindow(pRenderTarget, this); + if (surfaceWindow) { + pRenderTarget->BeginDraw(); + rcPaint = PRectangle(pps->rcPaint.left, pps->rcPaint.top, pps->rcPaint.right, pps->rcPaint.bottom); + PRectangle rcClient = GetClientRectangle(); + paintingAllText = rcPaint.Contains(rcClient); + if (paintingAllText) { + //Platform::DebugPrintf("Performing full text paint\n"); + } else { + //Platform::DebugPrintf("Performing partial paint %d .. %d\n", rcPaint.top, rcPaint.bottom); + } + Paint(surfaceWindow, rcPaint); + surfaceWindow->Release(); + HRESULT hr = pRenderTarget->EndDraw(); + if (hr == D2DERR_RECREATE_TARGET) { + DropRenderTarget(); + } } - Paint(surfaceWindow, rcPaint); - surfaceWindow->Release(); - HRESULT hr = pRenderTarget->EndDraw(); - if (hr == D2DERR_RECREATE_TARGET) { - DropRenderTarget(); - } } if (hRgnUpdate) { ::DeleteRgn(hRgnUpdate); @@ -1131,6 +1139,11 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam case SCI_SETTECHNOLOGY: if ((wParam == SC_TECHNOLOGY_DEFAULT) || (wParam == SC_TECHNOLOGY_DIRECTWRITE)) { if (technology != static_cast<int>(wParam)) { + if (static_cast<int>(wParam) == SC_TECHNOLOGY_DIRECTWRITE) { + if (!LoadD2D()) + // Failed to load Direct2D or DirectWrite so no effect + return 0; + } technology = wParam; // Invalidate all cached information including layout. InvalidateStyleRedraw(); |