diff options
| -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();  | 
