diff options
Diffstat (limited to 'win32')
| -rw-r--r-- | win32/PlatWin.cxx | 1214 | ||||
| -rw-r--r-- | win32/PlatWin.h | 13 | ||||
| -rw-r--r-- | win32/ScintillaWin.cxx | 180 | 
3 files changed, 1189 insertions, 218 deletions
| diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index 0ccc8aa13..00e0bf576 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -26,6 +26,8 @@  #include <commctrl.h>  #include <richedit.h>  #include <windowsx.h> +#include <d2d1.h> +#include <dwrite.h>  #include "Platform.h"  #include "UniConversion.h" @@ -195,6 +197,88 @@ void Palette::Allocate(Window &) {  	}  } +IDWriteFactory *pIDWriteFactory = 0; +ID2D1Factory *pD2DFactory = 0; + +bool LoadD2D() { +	static bool triedLoadingD2D = false; +	static HMODULE hDLLD2D = 0; +	static HMODULE hDLLDWrite = 0; +	if (!triedLoadingD2D) { +		typedef HRESULT (WINAPI *D2D1CFSig)(D2D1_FACTORY_TYPE factoryType, REFIID riid, +			CONST D2D1_FACTORY_OPTIONS *pFactoryOptions, IUnknown **factory); +		typedef HRESULT (WINAPI *DWriteCFSig)(DWRITE_FACTORY_TYPE factoryType, REFIID iid, +			IUnknown **factory); + +		hDLLD2D = ::LoadLibrary(TEXT("D2D1.DLL")); +		if (hDLLD2D) { +			D2D1CFSig fnD2DCF = (D2D1CFSig)::GetProcAddress(hDLLD2D, "D2D1CreateFactory"); +			if (fnD2DCF) { +				// A single threaded factory as Scintilla always draw on the GUI thread +				fnD2DCF(D2D1_FACTORY_TYPE_SINGLE_THREADED, +					__uuidof(ID2D1Factory), +					0, +					reinterpret_cast<IUnknown**>(&pD2DFactory)); +			} +		} +		hDLLDWrite = ::LoadLibrary(TEXT("DWRITE.DLL")); +		if (hDLLDWrite) { +			DWriteCFSig fnDWCF = (DWriteCFSig)::GetProcAddress(hDLLDWrite, "DWriteCreateFactory"); +			if (fnDWCF) { +				fnDWCF(DWRITE_FACTORY_TYPE_SHARED, +					__uuidof(IDWriteFactory), +					reinterpret_cast<IUnknown**>(&pIDWriteFactory)); +			} +		} +	} +	triedLoadingD2D = true; +	return pIDWriteFactory && pD2DFactory; +} + +struct FormatAndMetrics { +	int technology; +	HFONT hfont; +	IDWriteTextFormat *pTextFormat; +	int extraFontFlag; +	FLOAT yAscent; +	FLOAT yDescent; +	FormatAndMetrics(HFONT hfont_, int extraFontFlag_) :  +		technology(SCWIN_TECH_GDI), hfont(hfont_), pTextFormat(0), extraFontFlag(extraFontFlag_), yAscent(2), yDescent(1) { +	} +	FormatAndMetrics(IDWriteTextFormat *pTextFormat_, int extraFontFlag_, FLOAT yAscent_, FLOAT yDescent_) :  +		technology(SCWIN_TECH_DIRECTWRITE), hfont(0), pTextFormat(pTextFormat_), extraFontFlag(extraFontFlag_), yAscent(yAscent_), yDescent(yDescent_) { +	} +	~FormatAndMetrics() { +		if (hfont) +			::DeleteObject(hfont); +		if (pTextFormat) +		pTextFormat->Release(); +		pTextFormat = 0; +		extraFontFlag = 0; +		yAscent = 2; +		yDescent = 1; +	} +	HFONT HFont(); +}; + +HFONT FormatAndMetrics::HFont() { +	if (technology == SCWIN_TECH_GDI) { +		return hfont; +	} else { +		LOGFONTW lf; +		memset(&lf, 0, sizeof(lf)); + +		HRESULT hr = pTextFormat->GetFontFamilyName(lf.lfFaceName, LF_FACESIZE); +		if (SUCCEEDED(hr)) { +			lf.lfWeight = pTextFormat->GetFontWeight(); +			lf.lfItalic = pTextFormat->GetFontStyle() == DWRITE_FONT_STYLE_ITALIC; +			lf.lfHeight = -static_cast<int>(pTextFormat->GetFontSize()); +			return ::CreateFontIndirectW(&lf); +		} +	} +	return 0; +} +  #ifndef CLEARTYPE_QUALITY  #define CLEARTYPE_QUALITY 5  #endif @@ -216,11 +300,28 @@ static BYTE Win32MapFontQuality(int extraFontFlag) {  	}  } -static void SetLogFont(LOGFONTA &lf, const char *faceName, int characterSet, int size, bool bold, bool italic, int extraFontFlag) { +static D2D1_TEXT_ANTIALIAS_MODE DWriteMapFontQuality(int extraFontFlag) { +	switch (extraFontFlag & SC_EFF_QUALITY_MASK) { + +		case SC_EFF_QUALITY_NON_ANTIALIASED: +			return D2D1_TEXT_ANTIALIAS_MODE_ALIASED; + +		case SC_EFF_QUALITY_ANTIALIASED: +			return D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; + +		case SC_EFF_QUALITY_LCD_OPTIMIZED: +			return D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; + +		default: +			return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; +	} +} + +static void SetLogFont(LOGFONTA &lf, const char *faceName, int characterSet, float size, int weight, bool italic, int extraFontFlag) {  	memset(&lf, 0, sizeof(lf));  	// The negative is to allow for leading -	lf.lfHeight = -(abs(size)); -	lf.lfWeight = bold ? FW_BOLD : FW_NORMAL; +	lf.lfHeight = -(abs(static_cast<int>(size + 0.5))); +	lf.lfWeight = weight;  	lf.lfItalic = static_cast<BYTE>(italic ? 1 : 0);  	lf.lfCharSet = static_cast<BYTE>(characterSet);  	lf.lfQuality = Win32MapFontQuality(extraFontFlag); @@ -232,71 +333,111 @@ static void SetLogFont(LOGFONTA &lf, const char *faceName, int characterSet, int   * If one font is the same as another, its hash will be the same, but if the hash is the   * same then they may still be different.   */ -static int HashFont(const char *faceName, int characterSet, int size, bool bold, bool italic, int extraFontFlag) { +static int HashFont(const FontParameters &fp) {  	return -		size ^ -		(characterSet << 10) ^ -		((extraFontFlag & SC_EFF_QUALITY_MASK) << 9) ^ -		(bold ? 0x10000000 : 0) ^ -		(italic ? 0x20000000 : 0) ^ -		faceName[0]; +		static_cast<int>(fp.size) ^ +		(fp.characterSet << 10) ^ +		((fp.extraFontFlag & SC_EFF_QUALITY_MASK) << 9) ^ +		((fp.weight/100) << 12) ^ +		(fp.italic ? 0x20000000 : 0) ^ +		(fp.technology << 15) ^ +		fp.faceName[0];  }  class FontCached : Font {  	FontCached *next;  	int usage; +	float size;  	LOGFONTA lf; +	int technology;  	int hash; -	FontCached(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_); +	FontCached(const FontParameters &fp);  	~FontCached() {} -	bool SameAs(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_); +	bool SameAs(const FontParameters &fp);  	virtual void Release();  	static FontCached *first;  public: -	static FontID FindOrCreate(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_); +	static FontID FindOrCreate(const FontParameters &fp);  	static void ReleaseId(FontID fid_);  };  FontCached *FontCached::first = 0; -FontCached::FontCached(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_) : -	next(0), usage(0), hash(0) { -	SetLogFont(lf, faceName_, characterSet_, size_, bold_, italic_, extraFontFlag_); -	hash = HashFont(faceName_, characterSet_, size_, bold_, italic_, extraFontFlag_); -	fid = ::CreateFontIndirectA(&lf); +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 (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]; +		UTF16FromUTF8(fp.faceName, strlen(fp.faceName)+1, wszFace, faceSize); +		FLOAT fHeight = fp.size; +		DWRITE_FONT_STYLE style = fp.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; +		HRESULT hr = pIDWriteFactory->CreateTextFormat(wszFace, NULL, +			static_cast<DWRITE_FONT_WEIGHT>(fp.weight), +			style, +			DWRITE_FONT_STRETCH_NORMAL, fHeight, L"en-us", &pTextFormat); +		if (SUCCEEDED(hr)) { +			pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); + +			const int maxLines = 2; +			DWRITE_LINE_METRICS lineMetrics[maxLines]; +			UINT32 lineCount = 0; +			FLOAT yAscent = 1.0f; +			FLOAT yDescent = 1.0f; +			IDWriteTextLayout *pTextLayout = 0; +			hr = pIDWriteFactory->CreateTextLayout(L"X", 1, pTextFormat, +					100.0f, 100.0f, &pTextLayout); +			if (SUCCEEDED(hr)) { +				hr = pTextLayout->GetLineMetrics(lineMetrics, maxLines, &lineCount); +				if (SUCCEEDED(hr)) { +					yAscent = lineMetrics[0].baseline; +					yDescent = lineMetrics[0].height - lineMetrics[0].baseline; +				} +				pTextLayout->Release(); +			} +			fid = reinterpret_cast<void *>(new FormatAndMetrics(pTextFormat, fp.extraFontFlag, yAscent, yDescent)); +		} +	}  	usage = 1;  } -bool FontCached::SameAs(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_) { +bool FontCached::SameAs(const FontParameters &fp) {  	return -		(lf.lfHeight == -(abs(size_))) && -		(lf.lfWeight == (bold_ ? FW_BOLD : FW_NORMAL)) && -		(lf.lfItalic == static_cast<BYTE>(italic_ ? 1 : 0)) && -		(lf.lfCharSet == characterSet_) && -		(lf.lfQuality == Win32MapFontQuality(extraFontFlag_)) && -		0 == strcmp(lf.lfFaceName,faceName_); +		(size == fp.size) && +		(lf.lfWeight == fp.weight) && +		(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);  }  void FontCached::Release() { -	if (fid) -		::DeleteObject(fid); +	delete reinterpret_cast<FormatAndMetrics *>(fid);  	fid = 0;  } -FontID FontCached::FindOrCreate(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_) { +FontID FontCached::FindOrCreate(const FontParameters &fp) {  	FontID ret = 0;  	::EnterCriticalSection(&crPlatformLock); -	int hashFind = HashFont(faceName_, characterSet_, size_, bold_, italic_, extraFontFlag_); +	int hashFind = HashFont(fp);  	for (FontCached *cur=first; cur; cur=cur->next) {  		if ((cur->hash == hashFind) && -			cur->SameAs(faceName_, characterSet_, size_, bold_, italic_, extraFontFlag_)) { +			cur->SameAs(fp)) {  			cur->usage++;  			ret = cur->fid;  		}  	}  	if (ret == 0) { -		FontCached *fc = new FontCached(faceName_, characterSet_, size_, bold_, italic_, extraFontFlag_); +		FontCached *fc = new FontCached(fp);  		if (fc) {  			fc->next = first;  			first = fc; @@ -335,35 +476,62 @@ Font::~Font() {  #define FONTS_CACHED -void Font::Create(const char *faceName, int characterSet, int size, -	bool bold, bool italic, int extraFontFlag) { +void Font::Create(const FontParameters &fp) {  	Release(); -#ifndef FONTS_CACHED -	LOGFONT lf; -	SetLogFont(lf, faceName, characterSet, size, bold, italic, extraFontFlag); -	fid = ::CreateFontIndirect(&lf); -#else -	if (faceName) -		fid = FontCached::FindOrCreate(faceName, characterSet, size, bold, italic, extraFontFlag); -#endif +	if (fp.faceName) +		fid = FontCached::FindOrCreate(fp);  }  void Font::Release() { -#ifndef FONTS_CACHED -	if (fid) -		::DeleteObject(fid); -#else  	if (fid)  		FontCached::ReleaseId(fid); -#endif  	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 SurfaceImpl : public Surface { +class SurfaceGDI : public Surface {  	bool unicodeMode;  	HDC hdc;  	bool hdcOwned; @@ -386,12 +554,12 @@ class SurfaceImpl : public Surface {  	void BrushColor(ColourAllocated back);  	void SetFont(Font &font_); -	// Private so SurfaceImpl objects can not be copied -	SurfaceImpl(const SurfaceImpl &); -	SurfaceImpl &operator=(const SurfaceImpl &); +	// Private so SurfaceGDI objects can not be copied +	SurfaceGDI(const SurfaceGDI &); +	SurfaceGDI &operator=(const SurfaceGDI &);  public: -	SurfaceImpl(); -	virtual ~SurfaceImpl(); +	SurfaceGDI(); +	virtual ~SurfaceGDI();  	void Init(WindowID wid);  	void Init(SurfaceID sid, WindowID wid); @@ -415,19 +583,19 @@ public:  	void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back);  	void Copy(PRectangle rc, Point from, Surface &surfaceSource); -	void DrawTextCommon(PRectangle rc, Font &font_, int ybase, const char *s, int len, UINT fuOptions); -	void DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); -	void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); -	void DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore); -	void MeasureWidths(Font &font_, const char *s, int len, int *positions); -	int WidthText(Font &font_, const char *s, int len); -	int WidthChar(Font &font_, char ch); -	int Ascent(Font &font_); -	int Descent(Font &font_); -	int InternalLeading(Font &font_); -	int ExternalLeading(Font &font_); -	int Height(Font &font_); -	int AverageCharWidth(Font &font_); +	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); @@ -441,7 +609,7 @@ public:  } //namespace Scintilla  #endif -SurfaceImpl::SurfaceImpl() : +SurfaceGDI::SurfaceGDI() :  	unicodeMode(false),  	hdc(0), 	hdcOwned(false),  	pen(0), 	penOld(0), @@ -459,11 +627,11 @@ SurfaceImpl::SurfaceImpl() :  	win9xACPSame = false;  } -SurfaceImpl::~SurfaceImpl() { +SurfaceGDI::~SurfaceGDI() {  	Release();  } -void SurfaceImpl::Release() { +void SurfaceGDI::Release() {  	if (penOld) {  		::SelectObject(reinterpret_cast<HDC>(hdc), penOld);  		::DeleteObject(pen); @@ -501,33 +669,33 @@ void SurfaceImpl::Release() {  	}  } -bool SurfaceImpl::Initialised() { +bool SurfaceGDI::Initialised() {  	return hdc != 0;  } -void SurfaceImpl::Init(WindowID) { +void SurfaceGDI::Init(WindowID) {  	Release();  	hdc = ::CreateCompatibleDC(NULL);  	hdcOwned = true;  	::SetTextAlign(reinterpret_cast<HDC>(hdc), TA_BASELINE);  } -void SurfaceImpl::Init(SurfaceID sid, WindowID) { +void SurfaceGDI::Init(SurfaceID sid, WindowID) {  	Release();  	hdc = reinterpret_cast<HDC>(sid);  	::SetTextAlign(reinterpret_cast<HDC>(hdc), TA_BASELINE);  } -void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID) { +void SurfaceGDI::InitPixMap(int width, int height, Surface *surface_, WindowID) {  	Release(); -	hdc = ::CreateCompatibleDC(static_cast<SurfaceImpl *>(surface_)->hdc); +	hdc = ::CreateCompatibleDC(static_cast<SurfaceGDI *>(surface_)->hdc);  	hdcOwned = true; -	bitmap = ::CreateCompatibleBitmap(static_cast<SurfaceImpl *>(surface_)->hdc, width, height); +	bitmap = ::CreateCompatibleBitmap(static_cast<SurfaceGDI *>(surface_)->hdc, width, height);  	bitmapOld = static_cast<HBITMAP>(::SelectObject(hdc, bitmap));  	::SetTextAlign(reinterpret_cast<HDC>(hdc), TA_BASELINE);  } -void SurfaceImpl::PenColour(ColourAllocated fore) { +void SurfaceGDI::PenColour(ColourAllocated fore) {  	if (pen) {  		::SelectObject(hdc, penOld);  		::DeleteObject(pen); @@ -538,7 +706,7 @@ void SurfaceImpl::PenColour(ColourAllocated fore) {  	penOld = static_cast<HPEN>(::SelectObject(reinterpret_cast<HDC>(hdc), pen));  } -void SurfaceImpl::BrushColor(ColourAllocated back) { +void SurfaceGDI::BrushColor(ColourAllocated back) {  	if (brush) {  		::SelectObject(hdc, brushOld);  		::DeleteObject(brush); @@ -551,46 +719,48 @@ void SurfaceImpl::BrushColor(ColourAllocated back) {  	brushOld = static_cast<HBRUSH>(::SelectObject(hdc, brush));  } -void SurfaceImpl::SetFont(Font &font_) { +void SurfaceGDI::SetFont(Font &font_) {  	if (font_.GetID() != font) { +		FormatAndMetrics *pfm = reinterpret_cast<FormatAndMetrics *>(font_.GetID()); +		PLATFORM_ASSERT(pfm->technology == SCWIN_TECH_GDI);  		if (fontOld) { -			::SelectObject(hdc, font_.GetID()); +			::SelectObject(hdc, pfm->hfont);  		} else { -			fontOld = static_cast<HFONT>(::SelectObject(hdc, font_.GetID())); +			fontOld = static_cast<HFONT>(::SelectObject(hdc, pfm->hfont));  		} -		font = reinterpret_cast<HFONT>(font_.GetID()); +		font = reinterpret_cast<HFONT>(pfm->hfont);  	}  } -int SurfaceImpl::LogPixelsY() { +int SurfaceGDI::LogPixelsY() {  	return ::GetDeviceCaps(hdc, LOGPIXELSY);  } -int SurfaceImpl::DeviceHeightFont(int points) { +int SurfaceGDI::DeviceHeightFont(int points) {  	return ::MulDiv(points, LogPixelsY(), 72);  } -void SurfaceImpl::MoveTo(int x_, int y_) { +void SurfaceGDI::MoveTo(int x_, int y_) {  	::MoveToEx(hdc, x_, y_, 0);  } -void SurfaceImpl::LineTo(int x_, int y_) { +void SurfaceGDI::LineTo(int x_, int y_) {  	::LineTo(hdc, x_, y_);  } -void SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) { +void SurfaceGDI::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) {  	PenColour(fore);  	BrushColor(back);  	::Polygon(hdc, reinterpret_cast<POINT *>(pts), npts);  } -void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) { +void SurfaceGDI::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) {  	PenColour(fore);  	BrushColor(back);  	::Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);  } -void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) { +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); @@ -598,10 +768,10 @@ void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) {  	::ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE, &rcw, TEXT(""), 0, NULL);  } -void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) { +void SurfaceGDI::FillRectangle(PRectangle rc, Surface &surfacePattern) {  	HBRUSH br; -	if (static_cast<SurfaceImpl &>(surfacePattern).bitmap) -		br = ::CreatePatternBrush(static_cast<SurfaceImpl &>(surfacePattern).bitmap); +	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); @@ -609,7 +779,7 @@ void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) {  	::DeleteObject(br);  } -void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) { +void SurfaceGDI::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) {  	PenColour(fore);  	BrushColor(back);  	::RoundRect(hdc, @@ -645,7 +815,7 @@ static DWORD dwordFromBGRA(byte b, byte g, byte r, byte a) {  	return converter.val;  } -void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, +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)); @@ -704,7 +874,7 @@ void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated  	}  } -void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) { +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) @@ -743,58 +913,21 @@ void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsi  	}  } -void SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) { +void SurfaceGDI::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) {  	PenColour(fore);  	BrushColor(back);  	::Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom);  } -void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) { +void SurfaceGDI::Copy(PRectangle rc, Point from, Surface &surfaceSource) {  	::BitBlt(hdc,  		rc.left, rc.top, rc.Width(), rc.Height(), -		static_cast<SurfaceImpl &>(surfaceSource).hdc, from.x, from.y, SRCCOPY); +		static_cast<SurfaceGDI &>(surfaceSource).hdc, from.x, from.y, SRCCOPY);  } -// 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; -		} -	} -}; +typedef VarBuffer<int, stackBufferLength> TextPositionsI; -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<int, stackBufferLength> TextPositions; - -void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, int ybase, const char *s, int len, UINT fuOptions) { +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}; @@ -838,21 +971,21 @@ void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, int ybase, const ch  	}  } -void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, +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 SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, +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 SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, +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++) { @@ -866,7 +999,7 @@ void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, con  	}  } -int SurfaceImpl::WidthText(Font &font_, const char *s, int len) { +XYPOSITION SurfaceGDI::WidthText(Font &font_, const char *s, int len) {  	SetFont(font_);  	SIZE sz={0,0};  	if ((!unicodeMode) && (IsNT() || (codePage==0) || win9xACPSame)) { @@ -878,13 +1011,13 @@ int SurfaceImpl::WidthText(Font &font_, const char *s, int len) {  	return sz.cx;  } -void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positions) { +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); -		TextPositions poses(tbuf.tlen); +		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 @@ -928,19 +1061,19 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi  		int startOffset = 0;  		while (len > 0) {  			int lenBlock = Platform::Minimum(len, maxLenText); -			if (!::GetTextExtentExPointA(hdc, s, lenBlock, maxWidthMeasure, &fit, positions, &sz)) { +			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++) -					positions[i] = positions[fit-1]; -			} else if (startOffset > 0) { -				for (int i=0;i<lenBlock;i++) -					positions[i] += startOffset; +				for (int i = fit;i<lenBlock;i++) +					poses.buffer[i] = poses.buffer[fit-1];  			} -			startOffset = positions[lenBlock-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; @@ -948,7 +1081,7 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi  	} else {  		// Support Asian string display in 9x English  		const TextWide tbuf(s, len, unicodeMode, codePage); -		TextPositions poses(tbuf.tlen); +		TextPositionsI poses(tbuf.tlen);  		for (int widthSS=0; widthSS<tbuf.tlen; widthSS++) {  			::GetTextExtentPoint32W(hdc, tbuf.buffer, widthSS+1, &sz);  			poses.buffer[widthSS] = sz.cx; @@ -970,56 +1103,56 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi  	}  } -int SurfaceImpl::WidthChar(Font &font_, char ch) { +XYPOSITION SurfaceGDI::WidthChar(Font &font_, char ch) {  	SetFont(font_);  	SIZE sz;  	::GetTextExtentPoint32A(hdc, &ch, 1, &sz);  	return sz.cx;  } -int SurfaceImpl::Ascent(Font &font_) { +XYPOSITION SurfaceGDI::Ascent(Font &font_) {  	SetFont(font_);  	TEXTMETRIC tm;  	::GetTextMetrics(hdc, &tm);  	return tm.tmAscent;  } -int SurfaceImpl::Descent(Font &font_) { +XYPOSITION SurfaceGDI::Descent(Font &font_) {  	SetFont(font_);  	TEXTMETRIC tm;  	::GetTextMetrics(hdc, &tm);  	return tm.tmDescent;  } -int SurfaceImpl::InternalLeading(Font &font_) { +XYPOSITION SurfaceGDI::InternalLeading(Font &font_) {  	SetFont(font_);  	TEXTMETRIC tm;  	::GetTextMetrics(hdc, &tm);  	return tm.tmInternalLeading;  } -int SurfaceImpl::ExternalLeading(Font &font_) { +XYPOSITION SurfaceGDI::ExternalLeading(Font &font_) {  	SetFont(font_);  	TEXTMETRIC tm;  	::GetTextMetrics(hdc, &tm);  	return tm.tmExternalLeading;  } -int SurfaceImpl::Height(Font &font_) { +XYPOSITION SurfaceGDI::Height(Font &font_) {  	SetFont(font_);  	TEXTMETRIC tm;  	::GetTextMetrics(hdc, &tm);  	return tm.tmHeight;  } -int SurfaceImpl::AverageCharWidth(Font &font_) { +XYPOSITION SurfaceGDI::AverageCharWidth(Font &font_) {  	SetFont(font_);  	TEXTMETRIC tm;  	::GetTextMetrics(hdc, &tm);  	return tm.tmAveCharWidth;  } -int SurfaceImpl::SetPalette(Palette *pal, bool inBackGround) { +int SurfaceGDI::SetPalette(Palette *pal, bool inBackGround) {  	if (paletteOld) {  		::SelectPalette(hdc, paletteOld, TRUE);  	} @@ -1033,28 +1166,705 @@ int SurfaceImpl::SetPalette(Palette *pal, bool inBackGround) {  	return changes;  } -void SurfaceImpl::SetClip(PRectangle rc) { +void SurfaceGDI::SetClip(PRectangle rc) {  	::IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);  } -void SurfaceImpl::FlushCachedState() { +void SurfaceGDI::FlushCachedState() {  	pen = 0;  	brush = 0;  	font = 0;  } -void SurfaceImpl::SetUnicodeMode(bool unicodeMode_) { +void SurfaceGDI::SetUnicodeMode(bool unicodeMode_) {  	unicodeMode=unicodeMode_;  } -void SurfaceImpl::SetDBCSMode(int codePage_) { +void SurfaceGDI::SetDBCSMode(int codePage_) {  	// No action on window as automatically handled by system.  	codePage = codePage_;  	win9xACPSame = !IsNT() && ((unsigned int)codePage == ::GetACP());  } -Surface *Surface::Allocate() { -	return new SurfaceImpl; +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +class SurfaceD2D : public Surface { +	bool unicodeMode; +	int x, y; + +	int codePage; + +	ID2D1RenderTarget *pRenderTarget; +	bool ownRenderTarget; +	int clipsActive; + +	IDWriteTextFormat *pTextFormat; +	FLOAT yAscent; +	FLOAT yDescent; + +	ID2D1SolidColorBrush *pBrush; + +	int logPixelsY; +	float dpiScaleX; +	float dpiScaleY; + +	void SetFont(Font &font_); + +	// Private so SurfaceD2D objects can not be copied +	SurfaceD2D(const SurfaceD2D &); +	SurfaceD2D &operator=(const SurfaceD2D &); +public: +	SurfaceD2D(); +	virtual ~SurfaceD2D(); + +	void SetScale(); +	void Init(WindowID wid); +	void Init(SurfaceID sid, WindowID wid); +	void InitPixMap(int width, int height, Surface *surface_, WindowID wid); + +	void Release(); +	bool Initialised(); + +	HRESULT FlushDrawing(); + +	void PenColour(ColourAllocated fore); +	void D2DPenColour(ColourAllocated fore, int alpha=255); +	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 + +SurfaceD2D::SurfaceD2D() : +	unicodeMode(false), +	x(0), y(0) { + +	codePage = 0; + +	pRenderTarget = NULL; +	ownRenderTarget = false; +	clipsActive = 0; + +	// From selected font +	pTextFormat = NULL; +	yAscent = 2; +	yDescent = 1; + +	pBrush = NULL; + +	logPixelsY = 72; +	dpiScaleX = 1.0; +	dpiScaleY = 1.0; +} + +SurfaceD2D::~SurfaceD2D() { +	Release(); +} + +void SurfaceD2D::Release() { +	if (pBrush) { +		pBrush->Release(); +		pBrush = 0; +	} +	if (pRenderTarget) { +		while (clipsActive) { +			pRenderTarget->PopAxisAlignedClip(); +			clipsActive--; +		} +		if (ownRenderTarget) { +			pRenderTarget->Release(); +		} +		pRenderTarget = 0; +	} +} + +void SurfaceD2D::SetScale() { +	HDC hdcMeasure = ::CreateCompatibleDC(NULL); +	logPixelsY = ::GetDeviceCaps(hdcMeasure, LOGPIXELSY); +	dpiScaleX = ::GetDeviceCaps(hdcMeasure, LOGPIXELSX) / 96.0f; +	dpiScaleY = logPixelsY / 96.0f; +	::DeleteDC(hdcMeasure); +} + +bool SurfaceD2D::Initialised() { +	return pRenderTarget != 0; +} + +HRESULT SurfaceD2D::FlushDrawing() { +	return pRenderTarget->Flush(); +} + +void SurfaceD2D::Init(WindowID /* wid */) { +	Release(); +	SetScale(); +} + +void SurfaceD2D::Init(SurfaceID sid, WindowID) { +	Release(); +	SetScale(); +	pRenderTarget = reinterpret_cast<ID2D1HwndRenderTarget *>(sid); +} + +void SurfaceD2D::InitPixMap(int width, int height, Surface *surface_, WindowID) { +	Release(); +	SetScale(); +	SurfaceD2D *psurfOther = static_cast<SurfaceD2D *>(surface_); +	ID2D1BitmapRenderTarget *pCompatibleRenderTarget = NULL; +	HRESULT hr = psurfOther->pRenderTarget->CreateCompatibleRenderTarget( +		D2D1::SizeF(width, height), &pCompatibleRenderTarget); +	if (SUCCEEDED(hr)) { +		pRenderTarget = pCompatibleRenderTarget; +		pRenderTarget->BeginDraw(); +		ownRenderTarget = true; +	} +} + +void SurfaceD2D::PenColour(ColourAllocated fore) { +	D2DPenColour(fore); +} + +void SurfaceD2D::D2DPenColour(ColourAllocated fore, int alpha) { +	if (pRenderTarget) { +		D2D_COLOR_F col; +		col.r = (fore.AsLong() & 0xff) / 255.0; +		col.g = ((fore.AsLong() & 0xff00) >> 8) / 255.0; +		col.b = (fore.AsLong() >> 16) / 255.0; +		col.a = alpha / 255.0; +		if (pBrush) { +			pBrush->SetColor(col); +		} else { +			HRESULT hr = pRenderTarget->CreateSolidColorBrush(col, &pBrush); +			if (!SUCCEEDED(hr) && pBrush) {						 +				pBrush->Release(); +				pBrush = 0; +			} +		} +	} +} + +void SurfaceD2D::SetFont(Font &font_) { +	FormatAndMetrics *pfm = reinterpret_cast<FormatAndMetrics *>(font_.GetID()); +	PLATFORM_ASSERT(pfm->technology == SCWIN_TECH_DIRECTWRITE); +	pTextFormat = pfm->pTextFormat; +	yAscent = pfm->yAscent; +	yDescent = pfm->yDescent; +	if (pRenderTarget) { +		pRenderTarget->SetTextAntialiasMode(DWriteMapFontQuality(pfm->extraFontFlag)); +	} +} + +int SurfaceD2D::LogPixelsY() { +	return logPixelsY; +} + +int SurfaceD2D::DeviceHeightFont(int points) { +	return ::MulDiv(points, LogPixelsY(), 72); +} + +void SurfaceD2D::MoveTo(int x_, int y_) { +	x = x_; +	y = y_; +} + +static int Delta(int difference) { +	if (difference < 0) +		return -1; +	else if (difference > 0) +		return 1; +	else +		return 0; +} + +static int RoundFloat(float f) { +	return int(f+0.5); +} + +void SurfaceD2D::LineTo(int x_, int y_) { +	if (pRenderTarget) { +		int xDiff = x_ - x; +		int xDelta = Delta(xDiff); +		int yDiff = y_ - y; +		int yDelta = Delta(yDiff); +		if ((xDiff == 0) || (yDiff == 0)) { +			// Horizontal or vertical lines can be more precisely drawn as a filled rectangle +			int xEnd = x_ - xDelta; +			int left = Platform::Minimum(x, xEnd); +			int width = abs(x - xEnd) + 1; +			int yEnd = y_ - yDelta; +			int top = Platform::Minimum(y, yEnd); +			int height = abs(y - yEnd) + 1; +			D2D1_RECT_F rectangle1 = D2D1::RectF(left, top, left+width, top+height); +			pRenderTarget->FillRectangle(&rectangle1, pBrush); +		} else if ((abs(xDiff) == abs(yDiff))) { +			// 45 degree slope +			pRenderTarget->DrawLine(D2D1::Point2F(x + 0.5, y + 0.5),  +				D2D1::Point2F(x_ + 0.5 - xDelta, y_ + 0.5 - yDelta), pBrush); +		} else { +			// Line has a different slope so difficult to avoid last pixel +			pRenderTarget->DrawLine(D2D1::Point2F(x + 0.5, y + 0.5),  +				D2D1::Point2F(x_ + 0.5, y_ + 0.5), pBrush); +		} +		x = x_; +		y = y_; +	} +} + +void SurfaceD2D::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) { +	if (pRenderTarget) { +		ID2D1Factory *pFactory = 0; +		pRenderTarget->GetFactory(&pFactory); +		ID2D1PathGeometry *geometry=0; +		HRESULT hr = pFactory->CreatePathGeometry(&geometry); +		if (SUCCEEDED(hr)) { +			ID2D1GeometrySink *sink = 0; +			hr = geometry->Open(&sink); +			if (SUCCEEDED(hr)) { +				sink->BeginFigure(D2D1::Point2F(pts[0].x + 0.5f, pts[0].y + 0.5f), D2D1_FIGURE_BEGIN_FILLED); +				for (size_t i=1; i<static_cast<size_t>(npts); i++) { +					sink->AddLine(D2D1::Point2F(pts[i].x + 0.5f, pts[i].y + 0.5f)); +				} +				sink->EndFigure(D2D1_FIGURE_END_CLOSED); +				sink->Close(); +				sink->Release(); + +				D2DPenColour(back); +				pRenderTarget->FillGeometry(geometry,pBrush); +				D2DPenColour(fore); +				pRenderTarget->DrawGeometry(geometry,pBrush); +			} + +			geometry->Release(); +		} +	} +} + +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); +		D2DPenColour(back); +		pRenderTarget->FillRectangle(&rectangle1, pBrush); +		D2DPenColour(fore); +		pRenderTarget->DrawRectangle(&rectangle1, pBrush); +	} +} + +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); +        pRenderTarget->FillRectangle(&rectangle1, pBrush); +	} +} + +void SurfaceD2D::FillRectangle(PRectangle rc, Surface &surfacePattern) { +	SurfaceD2D &surfOther = static_cast<SurfaceD2D &>(surfacePattern); +	surfOther.FlushDrawing(); +	ID2D1Bitmap *pBitmap = NULL; +	ID2D1BitmapRenderTarget *pCompatibleRenderTarget = reinterpret_cast<ID2D1BitmapRenderTarget *>( +		surfOther.pRenderTarget); +	HRESULT hr = pCompatibleRenderTarget->GetBitmap(&pBitmap); +	if (SUCCEEDED(hr)) { +		ID2D1BitmapBrush *pBitmapBrush = NULL; +		D2D1_BITMAP_BRUSH_PROPERTIES brushProperties = +	        D2D1::BitmapBrushProperties(D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP, +			D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR); +		// Create the bitmap brush. +		hr = pRenderTarget->CreateBitmapBrush(pBitmap, brushProperties, &pBitmapBrush); +		pBitmap->Release(); +		if (SUCCEEDED(hr)) { +			pRenderTarget->FillRectangle( +				D2D1::RectF(rc.left, rc.top, rc.right, rc.bottom), +				pBitmapBrush); +			pBitmapBrush->Release(); +		} +	} +} + +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), +			8, 8); +		D2DPenColour(back); +		pRenderTarget->FillRoundedRectangle(roundedRectFill, pBrush); + +		D2D1_ROUNDED_RECT roundedRect = D2D1::RoundedRect( +			D2D1::RectF(rc.left + 0.5, rc.top+0.5, rc.right - 0.5, rc.bottom-0.5), +			8, 8); +		D2DPenColour(fore); +		pRenderTarget->DrawRoundedRectangle(roundedRect, pBrush); +	} +} + +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( +			D2D1::RectF(rc.left+1.0, rc.top+1.0, rc.right-1.0, rc.bottom-1.0), +			cornerSize, cornerSize); +		D2DPenColour(fill, alphaFill); +		pRenderTarget->FillRoundedRectangle(roundedRectFill, pBrush); + +		D2D1_ROUNDED_RECT roundedRect = D2D1::RoundedRect( +			D2D1::RectF(rc.left + 0.5, rc.top+0.5, rc.right - 0.5, rc.bottom-0.5), +			cornerSize, cornerSize); +		D2DPenColour(outline, alphaOutline); +		pRenderTarget->DrawRoundedRectangle(roundedRect, pBrush); +	} +} + +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; +		rc.right = rc.left + width; +		if (rc.Height() > height) +			rc.top += (rc.Height() - height) / 2; +		rc.bottom = rc.top + height; + +		std::vector<unsigned char> image(height * width * 4); +		for (int y=0; y<height; y++) { +			for (int x=0; x<width; x++) { +				unsigned char *pixel = &image[0] + (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++; +			} +		} + +		ID2D1Bitmap *bitmap = 0; +		D2D1_SIZE_U size = D2D1::SizeU(width, height); +		D2D1_BITMAP_PROPERTIES props = {{DXGI_FORMAT_B8G8R8A8_UNORM,	 +		    D2D1_ALPHA_MODE_PREMULTIPLIED}, 72.0, 72.0}; +		HRESULT hr = pRenderTarget->CreateBitmap(size, &image[0], +                  width * 4, &props, &bitmap); +		if (SUCCEEDED(hr)) { +			D2D1_RECT_F rcDestination = {rc.left, rc.top, rc.right, rc.bottom}; +			pRenderTarget->DrawBitmap(bitmap, rcDestination); +		} +		bitmap->Release(); +	} +} + +void SurfaceD2D::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) { +	if (pRenderTarget) { +		FLOAT radius = rc.Width() / 2.0f - 1.0f; +		D2D1_ELLIPSE ellipse = D2D1::Ellipse( +			D2D1::Point2F((rc.left + rc.right) / 2.0f, (rc.top + rc.bottom) / 2.0f), +			radius,radius); + +		PenColour(back); +		pRenderTarget->FillEllipse(ellipse, pBrush); +		PenColour(fore); +		pRenderTarget->DrawEllipse(ellipse, pBrush); +	} +} + +void SurfaceD2D::Copy(PRectangle rc, Point from, Surface &surfaceSource) { +	SurfaceD2D &surfOther = static_cast<SurfaceD2D &>(surfaceSource); +	surfOther.FlushDrawing(); +	ID2D1BitmapRenderTarget *pCompatibleRenderTarget = reinterpret_cast<ID2D1BitmapRenderTarget *>( +		surfOther.pRenderTarget); +	ID2D1Bitmap *pBitmap = NULL; +	HRESULT hr = pCompatibleRenderTarget->GetBitmap(&pBitmap); +	if (SUCCEEDED(hr)) { +		D2D1_RECT_F rcDestination = {rc.left, rc.top, rc.right, rc.bottom}; +		D2D1_RECT_F rcSource = {from.x, from.y, from.x + rc.Width(), from.y + rc.Height()}; +		pRenderTarget->DrawBitmap(pBitmap, rcDestination, 1.0f,  +			D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR, rcSource); +		pRenderTarget->Flush(); +		pBitmap->Release(); +	} +} + +void SurfaceD2D::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT) { +	SetFont(font_); +	RECT rcw = RectFromPRectangle(rc); + +	// Use Unicode calls +	const TextWide tbuf(s, len, unicodeMode, codePage); +	if (pRenderTarget && pTextFormat && pBrush) { +		 +		// Explicitly creating a text layout appears a little faster  +		IDWriteTextLayout *pTextLayout; +		HRESULT hr = pIDWriteFactory->CreateTextLayout(tbuf.buffer, tbuf.tlen, pTextFormat, +				rc.Width(), rc.Height(), &pTextLayout); +		if (SUCCEEDED(hr)) { +			D2D1_POINT_2F origin = {rc.left, ybase-yAscent}; +			pRenderTarget->DrawTextLayout(origin, pTextLayout, pBrush, D2D1_DRAW_TEXT_OPTIONS_NONE); +		} else { +			D2D1_RECT_F layoutRect = D2D1::RectF( +				static_cast<FLOAT>(rcw.left) / dpiScaleX, +				static_cast<FLOAT>(ybase-yAscent) / dpiScaleY, +				static_cast<FLOAT>(rcw.right + 1) / dpiScaleX, +				static_cast<FLOAT>(rcw.bottom) / dpiScaleY); +			pRenderTarget->DrawText(tbuf.buffer, tbuf.tlen, pTextFormat, layoutRect, pBrush, D2D1_DRAW_TEXT_OPTIONS_NONE); +		} +	} +} + +void SurfaceD2D::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, +	ColourAllocated fore, ColourAllocated back) { +	if (pRenderTarget) { +		FillRectangle(rc, back); +		D2DPenColour(fore); +		DrawTextCommon(rc, font_, ybase, s, len, ETO_OPAQUE); +	} +} + +void SurfaceD2D::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, +	ColourAllocated fore, ColourAllocated back) { +	if (pRenderTarget) { +		FillRectangle(rc, back); +		D2DPenColour(fore); +		DrawTextCommon(rc, font_, ybase, s, len, ETO_OPAQUE | ETO_CLIPPED); +	} +} + +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++) { +		if (s[i] != ' ') { +			if (pRenderTarget) { +				D2DPenColour(fore); +				DrawTextCommon(rc, font_, ybase, s, len, 0); +			} +			return; +		} +	} +} + +XYPOSITION SurfaceD2D::WidthText(Font &font_, const char *s, int len) { +	FLOAT width = 1.0; +	SetFont(font_); +	const TextWide tbuf(s, len, unicodeMode, codePage); +	if (pIDWriteFactory && pTextFormat) { +		// Create a layout +		IDWriteTextLayout *pTextLayout = 0; +		HRESULT hr = pIDWriteFactory->CreateTextLayout(tbuf.buffer, tbuf.tlen, pTextFormat, 1000.0, 1000.0, &pTextLayout); +		if (SUCCEEDED(hr)) { +			DWRITE_TEXT_METRICS textMetrics; +			pTextLayout->GetMetrics(&textMetrics); +			width = textMetrics.widthIncludingTrailingWhitespace; +			pTextLayout->Release(); +		} +	} +	return int(width + 0.5); +} + +void SurfaceD2D::MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions) { +	SetFont(font_); +	int fit = 0; +	const TextWide tbuf(s, len, unicodeMode, codePage); +	TextPositions poses(tbuf.tlen); +	fit = tbuf.tlen; +	const int clusters = 1000; +	DWRITE_CLUSTER_METRICS clusterMetrics[clusters]; +	UINT32 count = 0; +	if (pIDWriteFactory && pTextFormat) { +		SetFont(font_); +		// Create a layout +		IDWriteTextLayout *pTextLayout = 0; +		HRESULT hr = pIDWriteFactory->CreateTextLayout(tbuf.buffer, tbuf.tlen, pTextFormat, 10000.0, 1000.0, &pTextLayout); +		if (!SUCCEEDED(hr)) +			return; +		// For now, assuming WCHAR == cluster +		pTextLayout->GetClusterMetrics(clusterMetrics, clusters, &count); +		FLOAT position = 0.0f; +		size_t ti=0; +		for (size_t ci=0;ci<count;ci++) { +			position += clusterMetrics[ci].width; +			for (size_t inCluster=0; inCluster<clusterMetrics[ci].length; inCluster++) { +				//poses.buffer[ti++] = int(position + 0.5); +				poses.buffer[ti++] = position; +			} +		} +		PLATFORM_ASSERT(ti == static_cast<size_t>(tbuf.tlen)); +		pTextLayout->Release(); +	} +	if (unicodeMode) { +		// 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 (codePage == 0) { + +		// One character per position +		PLATFORM_ASSERT(len == tbuf.tlen); +		for (size_t kk=0;kk<static_cast<size_t>(len);kk++) { +			positions[kk] = poses.buffer[kk]; +		} + +	} else { + +		// May be more than one byte per position +		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 SurfaceD2D::WidthChar(Font &font_, char ch) { +	FLOAT width = 1.0; +	SetFont(font_); +	if (pIDWriteFactory && pTextFormat) { +		// Create a layout +		IDWriteTextLayout *pTextLayout = 0; +		const WCHAR wch = ch; +		HRESULT hr = pIDWriteFactory->CreateTextLayout(&wch, 1, pTextFormat, 1000.0, 1000.0, &pTextLayout); +		if (SUCCEEDED(hr)) { +			DWRITE_TEXT_METRICS textMetrics; +			pTextLayout->GetMetrics(&textMetrics); +			width = textMetrics.widthIncludingTrailingWhitespace; +			pTextLayout->Release(); +		} +	} +	return int(width + 0.5); +} + +XYPOSITION SurfaceD2D::Ascent(Font &font_) { +	SetFont(font_); +	return ceil(yAscent); +} + +XYPOSITION SurfaceD2D::Descent(Font &font_) { +	SetFont(font_); +	return ceil(yDescent); +} + +XYPOSITION SurfaceD2D::InternalLeading(Font &) { +	return 0; +} + +XYPOSITION SurfaceD2D::ExternalLeading(Font &) { +	return 1; +} + +XYPOSITION SurfaceD2D::Height(Font &font_) { +	return Ascent(font_) + Descent(font_); +} + +XYPOSITION SurfaceD2D::AverageCharWidth(Font &font_) { +	FLOAT width = 1.0; +	SetFont(font_); +	if (pIDWriteFactory && pTextFormat) { +		// Create a layout +		IDWriteTextLayout *pTextLayout = 0; +		const WCHAR wszAllAlpha[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +		HRESULT hr = pIDWriteFactory->CreateTextLayout(wszAllAlpha, wcslen(wszAllAlpha), pTextFormat, 1000.0, 1000.0, &pTextLayout); +		if (SUCCEEDED(hr)) { +			DWRITE_TEXT_METRICS textMetrics; +			pTextLayout->GetMetrics(&textMetrics); +			width = textMetrics.width / wcslen(wszAllAlpha); +			pTextLayout->Release(); +		} +	} +	return int(width + 0.5); +} + +int SurfaceD2D::SetPalette(Palette *, bool) { +	return 0; +} + +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); +		clipsActive++; +	} +} + +void SurfaceD2D::FlushCachedState() { +} + +void SurfaceD2D::SetUnicodeMode(bool unicodeMode_) { +	unicodeMode=unicodeMode_; +} + +void SurfaceD2D::SetDBCSMode(int codePage_) { +	// No action on window as automatically handled by system. +	codePage = codePage_; +} + +Surface *Surface::Allocate(int technology) { +	if (technology == SCWIN_TECH_GDI) +		return new SurfaceGDI; +	else +		return new SurfaceD2D;  }  Window::~Window() { @@ -1092,8 +1902,7 @@ void Window::SetPositionRelative(PRectangle rc, Window w) {  #ifdef MONITOR_DEFAULTTONULL  		// We're using the stub functionality of MultiMon.h to decay gracefully on machines  		// (ie, pre Win2000, Win95) that do not support the newer functions. -		RECT rcMonitor; -		memcpy(&rcMonitor, &rc, sizeof(rcMonitor));  // RECT and Rectangle are the same really. +		RECT rcMonitor = {rc.left, rc.top, rc.right, rc.bottom};  		MONITORINFO mi = {0};  		mi.cbSize = sizeof(mi); @@ -1365,6 +2174,7 @@ ListBox::~ListBox() {  class ListBoxX : public ListBox {  	int lineHeight;  	FontID fontCopy; +	int technology;  	RGBAImageSet images;  	LineToItem lti;  	HWND lb; @@ -1407,7 +2217,7 @@ class ListBoxX : public ListBox {  	static const Point ImageInset;	// Padding around image  public: -	ListBoxX() : lineHeight(10), fontCopy(0), lb(0), unicodeMode(false), +	ListBoxX() : lineHeight(10), fontCopy(0), technology(0), lb(0), unicodeMode(false),  		desiredVisibleRows(5), maxItemCharacters(0), aveCharWidth(8),  		parent(NULL), ctrlID(0), doubleClickAction(NULL), doubleClickActionData(NULL),  		widestItem(NULL), maxCharWidth(1), resizeHit(0), wheelDelta(0) { @@ -1419,7 +2229,7 @@ public:  		}  	}  	virtual void SetFont(Font &font); -	virtual void Create(Window &parent, int ctrlID, Point location_, int lineHeight_, bool unicodeMode_); +	virtual void Create(Window &parent, int ctrlID, Point location_, int lineHeight_, bool unicodeMode_, int technology_);  	virtual void SetAverageCharWidth(int width);  	virtual void SetVisibleRows(int rows);  	virtual int GetVisibleRows() const; @@ -1454,12 +2264,13 @@ ListBox *ListBox::Allocate() {  	return lb;  } -void ListBoxX::Create(Window &parent_, int ctrlID_, Point location_, int lineHeight_, bool unicodeMode_) { +void ListBoxX::Create(Window &parent_, int ctrlID_, Point location_, int lineHeight_, bool unicodeMode_, int technology_) {  	parent = &parent_;  	ctrlID = ctrlID_;  	location = location_;  	lineHeight = lineHeight_;  	unicodeMode = unicodeMode_; +	technology = technology_;  	HWND hwndParent = reinterpret_cast<HWND>(parent->GetID());  	HINSTANCE hinstanceParent = GetWindowInstance(hwndParent);  	// Window created as popup so not clipped within parent client area @@ -1471,17 +2282,19 @@ void ListBoxX::Create(Window &parent_, int ctrlID_, Point location_, int lineHei  		hinstanceParent,  		this); -	::MapWindowPoints(hwndParent, NULL, reinterpret_cast<POINT*>(&location), 1); +	POINT locationw = {location.x, location.y}; +	::MapWindowPoints(hwndParent, NULL, &locationw, 1); +	location = Point(locationw.x, locationw.y);  }  void ListBoxX::SetFont(Font &font) { -	LOGFONT lf; -	if (0 != ::GetObject(font.GetID(), sizeof(lf), &lf)) { +	if (font.GetID()) {  		if (fontCopy) {  			::DeleteObject(fontCopy);  			fontCopy = 0;  		} -		fontCopy = ::CreateFontIndirect(&lf); +		FormatAndMetrics *pfm = reinterpret_cast<FormatAndMetrics *>(font.GetID()); +		fontCopy = pfm->HFont();  		::SendMessage(lb, WM_SETFONT, reinterpret_cast<WPARAM>(fontCopy), 0);  	}  } @@ -1650,16 +2463,46 @@ void ListBoxX::Draw(DRAWITEMSTRUCT *pDrawItem) {  		// Draw the image, if any  		RGBAImage *pimage = images.Get(pixId);  		if (pimage) { -			Surface *surfaceItem = Surface::Allocate(); +			Surface *surfaceItem = Surface::Allocate(technology);  			if (surfaceItem) { -				surfaceItem->Init(pDrawItem->hDC, pDrawItem->hwndItem); -				int left = pDrawItem->rcItem.left + ItemInset.x + ImageInset.x; -				PRectangle rcImage(left, pDrawItem->rcItem.top, -					left + images.GetWidth(), pDrawItem->rcItem.bottom); -				surfaceItem->DrawRGBAImage(rcImage, -					pimage->GetWidth(), pimage->GetHeight(), pimage->Pixels()); -				delete surfaceItem; -				::SetTextAlign(pDrawItem->hDC, TA_TOP); +				if (technology == SCWIN_TECH_GDI) { +					surfaceItem->Init(pDrawItem->hDC, pDrawItem->hwndItem); +					int left = pDrawItem->rcItem.left + ItemInset.x + ImageInset.x; +					PRectangle rcImage(left, pDrawItem->rcItem.top, +						left + images.GetWidth(), pDrawItem->rcItem.bottom); +					surfaceItem->DrawRGBAImage(rcImage, +						pimage->GetWidth(), pimage->GetHeight(), pimage->Pixels()); +					delete surfaceItem; +					::SetTextAlign(pDrawItem->hDC, TA_TOP); +				} else { +					D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties( +						D2D1_RENDER_TARGET_TYPE_DEFAULT, +						D2D1::PixelFormat( +							DXGI_FORMAT_B8G8R8A8_UNORM, +							D2D1_ALPHA_MODE_IGNORE), +						0, +						0, +						D2D1_RENDER_TARGET_USAGE_NONE, +						D2D1_FEATURE_LEVEL_DEFAULT +						); +					ID2D1DCRenderTarget *pDCRT = 0; +					HRESULT hr = pD2DFactory->CreateDCRenderTarget(&props, &pDCRT); +					RECT rcWindow; +					GetClientRect(pDrawItem->hwndItem, &rcWindow); +					hr = pDCRT->BindDC(pDrawItem->hDC, &rcWindow); +					if (SUCCEEDED(hr)) { +						surfaceItem->Init(pDCRT, pDrawItem->hwndItem); +						pDCRT->BeginDraw(); +						int left = pDrawItem->rcItem.left + ItemInset.x + ImageInset.x; +						PRectangle rcImage(left, pDrawItem->rcItem.top, +							left + images.GetWidth(), pDrawItem->rcItem.bottom); +						surfaceItem->DrawRGBAImage(rcImage, +							pimage->GetWidth(), pimage->GetHeight(), pimage->Pixels()); +						delete surfaceItem; +						pDCRT->EndDraw(); +						pDCRT->Release(); +					} +				}  			}  		}  	} @@ -1726,7 +2569,9 @@ void ListBoxX::SetList(const char *list, char separator, char typesep) {  }  void ListBoxX::AdjustWindowRect(PRectangle *rc) const { -	::AdjustWindowRectEx(reinterpret_cast<RECT*>(rc), WS_THICKFRAME, false, WS_EX_WINDOWEDGE); +	RECT rcw = {rc->left, rc->top, rc->right, rc->bottom }; +	::AdjustWindowRectEx(&rcw, WS_THICKFRAME, false, WS_EX_WINDOWEDGE); +	*rc = PRectangle(rcw.left, rcw.top, rcw.right, rcw.bottom);  }  int ListBoxX::ItemHeight() const { @@ -1767,8 +2612,9 @@ void ListBoxX::SetRedraw(bool on) {  void ListBoxX::ResizeToCursor() {  	PRectangle rc = GetPosition(); -	Point pt; -	::GetCursorPos(reinterpret_cast<POINT*>(&pt)); +	POINT ptw; +	::GetCursorPos(&ptw); +	Point pt(ptw.x, ptw.y);  	pt.x += dragOffset.x;  	pt.y += dragOffset.y; diff --git a/win32/PlatWin.h b/win32/PlatWin.h new file mode 100644 index 000000000..dc3f8e432 --- /dev/null +++ b/win32/PlatWin.h @@ -0,0 +1,13 @@ +// Scintilla source code edit control +/** @file PlatWin.h + ** Implementation of platform facilities on Windows. + **/ +// Copyright 1998-2011 by Neil Hodgson <neilh@scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +extern bool IsNT(); +extern void Platform_Initialise(void *hInstance); +extern void Platform_Finalise(); +extern bool LoadD2D(); +extern ID2D1Factory *pD2DFactory; +extern IDWriteFactory *pIDWriteFactory; diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index d1f450479..a3c141aff 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -24,6 +24,9 @@  #include <richedit.h>  #include <windowsx.h> +#include <d2d1.h> +#include <dwrite.h> +  #include "Platform.h"  #include "ILexer.h" @@ -54,6 +57,7 @@  #include "Editor.h"  #include "ScintillaBase.h"  #include "UniConversion.h" +#include "PlatWin.h"  #ifdef SCI_LEXER  #include "ExternalLexer.h" @@ -87,11 +91,6 @@  #define SC_WIN_IDLE 5001 -// Functions imported from PlatWin -extern bool IsNT(); -extern void Platform_Initialise(void *hInstance); -extern void Platform_Finalise(); -  typedef BOOL (WINAPI *TrackMouseEventSig)(LPTRACKMOUSEEVENT);  // GCC has trouble with the standard COM ABI so do it the old C way with explicit vtables. @@ -197,6 +196,8 @@ class ScintillaWin :  	static HINSTANCE hInstance; +	ID2D1HwndRenderTarget *pRenderTarget; +  	ScintillaWin(HWND hwnd);  	ScintillaWin(const ScintillaWin &);  	virtual ~ScintillaWin(); @@ -204,6 +205,8 @@ class ScintillaWin :  	virtual void Initialise();  	virtual void Finalise(); +	void EnsureRenderTarget(); +	void DropRenderTarget();  	HWND MainHWND();  	static sptr_t DirectFunction( @@ -350,6 +353,8 @@ ScintillaWin::ScintillaWin(HWND hwnd) {  	sysCaretWidth = 0;  	sysCaretHeight = 0; +	pRenderTarget = 0; +  	keysAlwaysUnicode = false;  	caret.period = ::GetCaretBlinkTime(); @@ -384,12 +389,46 @@ void ScintillaWin::Finalise() {  	ScintillaBase::Finalise();  	SetTicking(false);  	SetIdle(false); +	DropRenderTarget();  	::RevokeDragDrop(MainHWND());  	if (SUCCEEDED(hrOle)) {  		::OleUninitialize();  	}  } +void ScintillaWin::EnsureRenderTarget() { +	if (pD2DFactory && !pRenderTarget) { +		RECT rc; +		HWND hw = MainHWND(); +		GetClientRect(hw, &rc); + +		D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top); + +		// Create a Direct2D render target. +#if 1 +		pD2DFactory->CreateHwndRenderTarget( +			D2D1::RenderTargetProperties(), +			D2D1::HwndRenderTargetProperties(hw, size), +			&pRenderTarget); +#else +		pD2DFactory->CreateHwndRenderTarget( +			D2D1::RenderTargetProperties( +				D2D1_RENDER_TARGET_TYPE_DEFAULT , +				D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), +				96.0f, 96.0f, D2D1_RENDER_TARGET_USAGE_NONE, D2D1_FEATURE_LEVEL_DEFAULT), +			D2D1::HwndRenderTargetProperties(hw, size), +			&pRenderTarget); +#endif +	} +} + +void ScintillaWin::DropRenderTarget() { +	if (pRenderTarget) { +		pRenderTarget->Release(); +		pRenderTarget = 0; +	} +} +  HWND ScintillaWin::MainHWND() {  	return reinterpret_cast<HWND>(wMain.GetID());  } @@ -505,18 +544,35 @@ LRESULT ScintillaWin::WndPaint(uptr_t wParam) {  		pps = &ps;  		::BeginPaint(MainHWND(), pps);  	} -	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); -		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();  	}  	if (hRgnUpdate) {  		::DeleteRgn(hRgnUpdate); @@ -674,6 +730,7 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam  			break;  		case WM_SIZE: { +				DropRenderTarget();  				//Platform::DebugPrintf("Scintilla WM_SIZE %d %d\n", LoWord(lParam), HiWord(lParam));  				ChangeSize();  			} @@ -1085,6 +1142,22 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam  		case SCI_GETKEYSUNICODE:  			return keysAlwaysUnicode; +		 +		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. +					DropGraphics(true); +					InvalidateStyleRedraw(); +				} +			} +			break;  #ifdef SCI_LEXER  		case SCI_LOADLEXERLIBRARY: @@ -1196,11 +1269,12 @@ bool ScintillaWin::PaintContains(PRectangle rc) {  	return contains;  } -void ScintillaWin::ScrollText(int linesToMove) { +void ScintillaWin::ScrollText(int /* linesToMove */) {  	//Platform::DebugPrintf("ScintillaWin::ScrollText %d\n", linesToMove); -	::ScrollWindow(MainHWND(), 0, -		vs.lineHeight * linesToMove, 0, 0); -	::UpdateWindow(MainHWND()); +	//::ScrollWindow(MainHWND(), 0, +	//	vs.lineHeight * linesToMove, 0, 0); +	//::UpdateWindow(MainHWND()); +	Redraw();  }  void ScintillaWin::UpdateSystemCaret() { @@ -2085,9 +2159,9 @@ void ScintillaWin::ImeStartComposition() {  			// The logfont for the IME is recreated here.  			int styleHere = (pdoc->StyleAt(sel.MainCaret())) & 31;  			LOGFONTA lf = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ""}; -			int sizeZoomed = vs.styles[styleHere].size + vs.zoomLevel; -			if (sizeZoomed <= 2)	// Hangs if sizeZoomed <= 1 -				sizeZoomed = 2; +			int sizeZoomed = vs.styles[styleHere].size + vs.zoomLevel * SC_FONT_SIZE_MULTIPLIER; +			if (sizeZoomed <= 2 * SC_FONT_SIZE_MULTIPLIER)	// Hangs if sizeZoomed <= 1 +				sizeZoomed = 2 * SC_FONT_SIZE_MULTIPLIER;  			AutoSurface surface(this);  			int deviceHeight = sizeZoomed;  			if (surface) { @@ -2095,7 +2169,7 @@ void ScintillaWin::ImeStartComposition() {  			}  			// The negative is to allow for leading  			lf.lfHeight = -(abs(deviceHeight)); -			lf.lfWeight = vs.styles[styleHere].bold ? FW_BOLD : FW_NORMAL; +			lf.lfWeight = vs.styles[styleHere].weight;  			lf.lfItalic = static_cast<BYTE>(vs.styles[styleHere].italic ? 1 : 0);  			lf.lfCharSet = DEFAULT_CHARSET;  			lf.lfFaceName[0] = '\0'; @@ -2290,7 +2364,9 @@ void ScintillaWin::HorizontalScrollMessage(WPARAM wParam) {  	HorizontalScrollTo(xPos);  } -void ScintillaWin::RealizeWindowPalette(bool inBackGround) { +void ScintillaWin::RealizeWindowPalette(bool) { +	// No support for palette with D2D +/*  	RefreshStyleData();  	HDC hdc = ::GetDC(MainHWND());  	// Select a stock font to prevent warnings from BoundsChecker @@ -2303,6 +2379,7 @@ void ScintillaWin::RealizeWindowPalette(bool inBackGround) {  		surfaceWindow->Release();  	}  	::ReleaseDC(MainHWND(), hdc); +*/  }  /** @@ -2310,9 +2387,13 @@ void ScintillaWin::RealizeWindowPalette(bool inBackGround) {   * This paint will not be abandoned.   */  void ScintillaWin::FullPaint() { -	HDC hdc = ::GetDC(MainHWND()); -	FullPaintDC(hdc); -	::ReleaseDC(MainHWND(), hdc); +	if (technology == SC_TECHNOLOGY_DEFAULT) { +		HDC hdc = ::GetDC(MainHWND()); +		FullPaintDC(hdc); +		::ReleaseDC(MainHWND(), hdc); +	} else { +		FullPaintDC(0); +	}  }  /** @@ -2323,10 +2404,24 @@ void ScintillaWin::FullPaintDC(HDC hdc) {  	paintState = painting;  	rcPaint = GetClientRectangle();  	paintingAllText = true; -	AutoSurface surfaceWindow(hdc, this); -	if (surfaceWindow) { -		Paint(surfaceWindow, rcPaint); -		surfaceWindow->Release(); +	if (technology == SC_TECHNOLOGY_DEFAULT) { +		AutoSurface surfaceWindow(hdc, this); +		if (surfaceWindow) { +			Paint(surfaceWindow, rcPaint); +			surfaceWindow->Release(); +		} +	} else { +		EnsureRenderTarget(); +		AutoSurface surfaceWindow(pRenderTarget, this); +		if (surfaceWindow) { +			pRenderTarget->BeginDraw(); +			Paint(surfaceWindow, rcPaint); +			surfaceWindow->Release(); +			HRESULT hr = pRenderTarget->EndDraw(); +			if (hr == D2DERR_RECREATE_TARGET) { +				DropRenderTarget(); +			} +		}  	}  	paintState = notPainting;  } @@ -2698,14 +2793,31 @@ sptr_t PASCAL ScintillaWin::CTWndProc(  			} else if (iMessage == WM_PAINT) {  				PAINTSTRUCT ps;  				::BeginPaint(hWnd, &ps); -				Surface *surfaceWindow = Surface::Allocate(); +				Surface *surfaceWindow = Surface::Allocate(sciThis->technology);  				if (surfaceWindow) { -					surfaceWindow->Init(ps.hdc, hWnd); +					ID2D1HwndRenderTarget *pCTRenderTarget = 0; +					RECT rc; +					GetClientRect(hWnd, &rc); +					// Create a Direct2D render target. +					if (sciThis->technology == SC_TECHNOLOGY_DEFAULT) { +						surfaceWindow->Init(ps.hdc, hWnd); +					} else { +						pD2DFactory->CreateHwndRenderTarget( +							D2D1::RenderTargetProperties(), +							D2D1::HwndRenderTargetProperties(hWnd, D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)), +							&pCTRenderTarget); +						surfaceWindow->Init(pCTRenderTarget, hWnd); +						pCTRenderTarget->BeginDraw(); +					}  					surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == sciThis->ct.codePage);  					surfaceWindow->SetDBCSMode(sciThis->ct.codePage);  					sciThis->ct.PaintCT(surfaceWindow); +					if (pCTRenderTarget) +						pCTRenderTarget->EndDraw();  					surfaceWindow->Release();  					delete surfaceWindow; +					if (pCTRenderTarget) +						pCTRenderTarget->Release();  				}  				::EndPaint(hWnd, &ps);  				return 0; | 
