diff options
Diffstat (limited to 'win32/PlatWin.cxx')
| -rw-r--r-- | win32/PlatWin.cxx | 954 | 
1 files changed, 560 insertions, 394 deletions
| diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index 6a2f103ba..acbb5f62d 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,30 @@ void Palette::Allocate(Window &) {  	}  } +static IDWriteFactory *pIDWriteFactory = 0; + +static void EnsureDWriteFactory() { +	// Construct +	if (!pIDWriteFactory) { +		DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, +			__uuidof(IDWriteFactory), +			reinterpret_cast<IUnknown**>(&pIDWriteFactory)); +	} +} + +struct FormatAndBaseline { +	IDWriteTextFormat *pTextFormat; +	FLOAT baseline; +	FormatAndBaseline(IDWriteTextFormat *pTextFormat_, FLOAT baseline_) :  +		pTextFormat(pTextFormat_), baseline(baseline_) { +	} +	~FormatAndBaseline() { +		pTextFormat->Release(); +		pTextFormat = 0; +		baseline = 1; +	} +}; +  #ifndef CLEARTYPE_QUALITY  #define CLEARTYPE_QUALITY 5  #endif @@ -247,28 +273,74 @@ class FontCached : Font {  	int usage;  	LOGFONTA lf;  	int hash; -	FontCached(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_); +	FontCached(const char *faceName_, int characterSet_, float size_, bool bold_, bool italic_, int extraFontFlag_);  	~FontCached() {} -	bool SameAs(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_); +	bool SameAs(const char *faceName_, int characterSet_, float size_, bool bold_, bool italic_, int extraFontFlag_);  	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 char *faceName_, int characterSet_, float size_, bool bold_, bool italic_, int extraFontFlag_);  	static void ReleaseId(FontID fid_);  };  FontCached *FontCached::first = 0; -FontCached::FontCached(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_) : +FontCached::FontCached(const char *faceName_, int characterSet_, float 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); +	fid = 0; +	EnsureDWriteFactory(); +	if (pIDWriteFactory) { +#ifdef OLD_CODE +		HFONT fontSave = static_cast<HFONT>(::SelectObject(hdc, font_.GetID())); +		DWORD sizeOLTM = ::GetOutlineTextMetrics(hdc, NULL, NULL); +		std::vector<char> vOLTM(sizeOLTM); +		LPOUTLINETEXTMETRIC potm = reinterpret_cast<LPOUTLINETEXTMETRIC>(&vOLTM[0]); +		DWORD worked = ::GetOutlineTextMetrics(hdc, sizeOLTM, potm); +		::SelectObject(hdc, fontSave); +		if (!worked) +			return; +		const WCHAR *pwcFamily = reinterpret_cast<WCHAR *>(&vOLTM[reinterpret_cast<size_t>(potm->otmpFamilyName)]); +		//const WCHAR *pwcFace = reinterpret_cast<WCHAR *>(&vOLTM[reinterpret_cast<size_t>(potm->otmpFaceName)]); +		FLOAT fHeight = potm->otmTextMetrics.tmHeight * 72.0f / 96.0f; +		bool italics = potm->otmTextMetrics.tmItalic != 0; +		bool bold = potm->otmTextMetrics.tmWeight >= FW_BOLD; +#endif +		IDWriteTextFormat *pTextFormat; +		const int faceSize = 200; +		WCHAR wszFace[faceSize]; +		UTF16FromUTF8(faceName_, strlen(faceName_)+1, wszFace, faceSize); +		FLOAT fHeight = size_; +		if (fHeight > 2000) +			fHeight = fHeight / 1000.0f; +		HRESULT hr = pIDWriteFactory->CreateTextFormat(wszFace, NULL, +			bold_ ? DWRITE_FONT_WEIGHT_SEMI_BOLD : DWRITE_FONT_WEIGHT_REGULAR, +			italic_ ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, +			DWRITE_FONT_STRETCH_NORMAL, fHeight, L"en-us", &pTextFormat); +		if (SUCCEEDED(hr)) { +			const int maxLines = 2; +			DWRITE_LINE_METRICS lineMetrics[maxLines]; +			UINT32 lineCount = 0; +			FLOAT baseline = 1.0f; +			IDWriteTextLayout *pTextLayout = 0; +			HRESULT hr = pIDWriteFactory->CreateTextLayout(L"X", 1, pTextFormat, +					100.0f, 100.0f, &pTextLayout); +			if (SUCCEEDED(hr)) { +				hr = pTextLayout->GetLineMetrics(lineMetrics, maxLines, &lineCount); +				if (SUCCEEDED(hr)) { +					baseline = lineMetrics[0].baseline; +				} +				pTextLayout->Release(); +			} +			fid = reinterpret_cast<void *>(new FormatAndBaseline(pTextFormat, baseline)); +		} +	}  	usage = 1;  } -bool FontCached::SameAs(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_) { +bool FontCached::SameAs(const char *faceName_, int characterSet_, float size_, bool bold_, bool italic_, int extraFontFlag_) {  	return  		(lf.lfHeight == -(abs(size_))) &&  		(lf.lfWeight == (bold_ ? FW_BOLD : FW_NORMAL)) && @@ -279,12 +351,11 @@ bool FontCached::SameAs(const char *faceName_, int characterSet_, int size_, boo  }  void FontCached::Release() { -	if (fid) -		::DeleteObject(fid); +	delete reinterpret_cast<FormatAndBaseline *>(fid);  	fid = 0;  } -FontID FontCached::FindOrCreate(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_) { +FontID FontCached::FindOrCreate(const char *faceName_, int characterSet_, float size_, bool bold_, bool italic_, int extraFontFlag_) {  	FontID ret = 0;  	::EnterCriticalSection(&crPlatformLock);  	int hashFind = HashFont(faceName_, characterSet_, size_, bold_, italic_, extraFontFlag_); @@ -335,27 +406,16 @@ Font::~Font() {  #define FONTS_CACHED -void Font::Create(const char *faceName, int characterSet, int size, +void Font::Create(const char *faceName, int characterSet, float size,  	bool bold, bool italic, int extraFontFlag) {  	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  }  void Font::Release() { -#ifndef FONTS_CACHED -	if (fid) -		::DeleteObject(fid); -#else  	if (fid)  		FontCached::ReleaseId(fid); -#endif  	fid = 0;  } @@ -367,23 +427,26 @@ class SurfaceImpl : 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 x, y;  	int codePage;  	// If 9x OS and current code page is same as ANSI code page.  	bool win9xACPSame; -	void BrushColor(ColourAllocated back); +	ID2D1RenderTarget *pRenderTarget; +	bool ownRenderTarget; +	bool needsEndDraw; +	int clipsActive; + +	IDWriteTextFormat *pTextFormat; +	FLOAT baseline; +	ID2D1SolidColorBrush *pBrush; +	float dpiScaleX; +	float dpiScaleY; +	bool hasBegun; +  	void SetFont(Font &font_);  	// Private so SurfaceImpl objects can not be copied @@ -393,13 +456,18 @@ public:  	SurfaceImpl();  	virtual ~SurfaceImpl(); +	void SetDWrite(HDC hdc);  	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_); @@ -415,19 +483,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,14 +509,13 @@ public:  } //namespace Scintilla  #endif +#pragma comment(lib, "d2d1.lib") +#pragma comment(lib, "dwrite.lib") +  SurfaceImpl::SurfaceImpl() :  	unicodeMode(false), -	hdc(0), 	hdcOwned(false), -	pen(0), 	penOld(0), -	brush(0), brushOld(0), -	font(0), 	fontOld(0), -	bitmap(0), bitmapOld(0), -	paletteOld(0) { +	hdc(0), hdcOwned(false), +	x(0), y(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 @@ -457,6 +524,17 @@ SurfaceImpl::SurfaceImpl() :  	codePage = 0;  	win9xACPSame = false; + +	pRenderTarget = NULL; +	ownRenderTarget = false; +	needsEndDraw = false; +	clipsActive = 0; +	pTextFormat = NULL; +	baseline = 1.0f; +	pBrush = NULL; +	dpiScaleX = 1.0; +	dpiScaleY = 1.0; +	hasBegun = false;  }  SurfaceImpl::~SurfaceImpl() { @@ -464,102 +542,107 @@ SurfaceImpl::~SurfaceImpl() {  }  void SurfaceImpl::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;  	} + +	if (pBrush) { +		pBrush->Release(); +		pBrush = 0; +	} +	if (pRenderTarget) { +		while (clipsActive) { +			pRenderTarget->PopAxisAlignedClip(); +			clipsActive--; +		} +		if (ownRenderTarget) { +			pRenderTarget->Release(); +		} +		pRenderTarget = 0; +	} +} + +// Ensures have pIDWriteFactory, and pRenderTarget +// If any fail, pRenderTarget will be NULL +void SurfaceImpl::SetDWrite(HDC hdc) { +	// Construct +	EnsureDWriteFactory(); +	dpiScaleX = GetDeviceCaps(hdc, LOGPIXELSX) / 96.0f; +	dpiScaleY = GetDeviceCaps(hdc, LOGPIXELSY) / 96.0f;  }  bool SurfaceImpl::Initialised() { -	return hdc != 0; +	return pRenderTarget != 0; +} + +HRESULT SurfaceImpl::FlushDrawing() { +	return pRenderTarget->Flush();  } -void SurfaceImpl::Init(WindowID) { +void SurfaceImpl::Init(WindowID wid) {  	Release();  	hdc = ::CreateCompatibleDC(NULL);  	hdcOwned = true;  	::SetTextAlign(reinterpret_cast<HDC>(hdc), TA_BASELINE); +	RECT rc; +	::GetClientRect(reinterpret_cast<HWND>(wid), &rc); +	SetDWrite(hdc);  }  void SurfaceImpl::Init(SurfaceID sid, WindowID) {  	Release(); -	hdc = reinterpret_cast<HDC>(sid); +	hdc = ::CreateCompatibleDC(NULL); +	hdcOwned = true; +	pRenderTarget = reinterpret_cast<ID2D1HwndRenderTarget *>(sid);  	::SetTextAlign(reinterpret_cast<HDC>(hdc), TA_BASELINE); +	SetDWrite(hdc);  }  void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID) {  	Release(); -	hdc = ::CreateCompatibleDC(static_cast<SurfaceImpl *>(surface_)->hdc); +	hdc = ::CreateCompatibleDC(NULL);	// Just for measurement  	hdcOwned = true; -	bitmap = ::CreateCompatibleBitmap(static_cast<SurfaceImpl *>(surface_)->hdc, width, height); -	bitmapOld = static_cast<HBITMAP>(::SelectObject(hdc, bitmap)); -	::SetTextAlign(reinterpret_cast<HDC>(hdc), TA_BASELINE); -} - -void SurfaceImpl::PenColour(ColourAllocated fore) { -	if (pen) { -		::SelectObject(hdc, penOld); -		::DeleteObject(pen); -		pen = 0; -		penOld = 0; +	SurfaceImpl *psurfOther = static_cast<SurfaceImpl *>(surface_); +	ID2D1BitmapRenderTarget *pCompatibleRenderTarget = NULL; +	HRESULT hr = psurfOther->pRenderTarget->CreateCompatibleRenderTarget( +		D2D1::SizeF(width, height), &pCompatibleRenderTarget); +	if (SUCCEEDED(hr)) { +		pRenderTarget = pCompatibleRenderTarget; +		pRenderTarget->BeginDraw(); +		ownRenderTarget = true; +		needsEndDraw = true;  	} -	pen = ::CreatePen(0,1,fore.AsLong()); -	penOld = static_cast<HPEN>(::SelectObject(reinterpret_cast<HDC>(hdc), pen));  } -void SurfaceImpl::BrushColor(ColourAllocated back) { -	if (brush) { -		::SelectObject(hdc, brushOld); -		::DeleteObject(brush); -		brush = 0; -		brushOld = 0; +void SurfaceImpl::PenColour(ColourAllocated fore) { +	D2DPenColour(fore); +} + +void SurfaceImpl::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; +			} +		}  	} -	// 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 SurfaceImpl::SetFont(Font &font_) { -	if (font_.GetID() != font) { -		if (fontOld) { -			::SelectObject(hdc, font_.GetID()); -		} else { -			fontOld = static_cast<HFONT>(::SelectObject(hdc, font_.GetID())); -		} -		font = reinterpret_cast<HFONT>(font_.GetID()); -	} +	FormatAndBaseline *pfabl = reinterpret_cast<FormatAndBaseline *>(font_.GetID()); +	pTextFormat = pfabl->pTextFormat; +	baseline = pfabl->baseline;  }  int SurfaceImpl::LogPixelsY() { @@ -571,142 +654,160 @@ int SurfaceImpl::DeviceHeightFont(int points) {  }  void SurfaceImpl::MoveTo(int x_, int y_) { -	::MoveToEx(hdc, x_, y_, 0); +	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 SurfaceImpl::LineTo(int x_, int y_) { -	::LineTo(hdc, x_, 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 SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) { -	PenColour(fore); -	BrushColor(back); -	::Polygon(hdc, reinterpret_cast<POINT *>(pts), npts); +	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 SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) { -	PenColour(fore); -	BrushColor(back); -	::Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom); +	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 SurfaceImpl::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); +	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 SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) { -	HBRUSH br; -	if (static_cast<SurfaceImpl &>(surfacePattern).bitmap) -		br = ::CreatePatternBrush(static_cast<SurfaceImpl &>(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); +	SurfaceImpl &surfOther = static_cast<SurfaceImpl &>(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 SurfaceImpl::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 +	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); -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; +		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 SurfaceImpl::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); -		} +	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); -		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); +		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 SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) { -	if (AlphaBlendFn && rc.Width() > 0) { -		HDC hMemDC = ::CreateCompatibleDC(reinterpret_cast<HDC>(hdc)); +	if (pRenderTarget) {  		if (rc.Width() > width)  			rc.left += (rc.Width() - width) / 2;  		rc.right = rc.left + width; @@ -714,15 +815,10 @@ void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsi  			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--) { +		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 + (y*width+x) * 4; +				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; @@ -731,28 +827,50 @@ void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsi  				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); +		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 SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) { -	PenColour(fore); -	BrushColor(back); -	::Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom); +	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 SurfaceImpl::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); +	SurfaceImpl &surfOther = static_cast<SurfaceImpl &>(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(); +	}  }  // Buffer to hold strings and string position arrays without always allocating on heap. @@ -792,109 +910,115 @@ public:  		}  	}  }; -typedef VarBuffer<int, stackBufferLength> TextPositions; +typedef VarBuffer<XYPOSITION, stackBufferLength> TextPositions; -void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, int ybase, const char *s, int len, UINT fuOptions) { +void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT) {  	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; -			} + +	// 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()+2, rc.Height(), &pTextLayout); +		if (SUCCEEDED(hr)) { +			D2D1_POINT_2F origin = {rc.left, ybase-baseline}; +			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-baseline) / 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 SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, +void SurfaceImpl::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); +	if (pRenderTarget) { +		FillRectangle(rc, back); +		D2DPenColour(fore); +		DrawTextCommon(rc, font_, ybase, s, len, ETO_OPAQUE); +	}  } -void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, +void SurfaceImpl::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); +	if (pRenderTarget) { +		FillRectangle(rc, back); +		D2DPenColour(fore); +		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 SurfaceImpl::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); +			if (pRenderTarget) { +				D2DPenColour(fore); +				DrawTextCommon(rc, font_, ybase, s, len, 0); +			}  			return;  		}  	}  } -int SurfaceImpl::WidthText(Font &font_, const char *s, int len) { +XYPOSITION SurfaceImpl::WidthText(Font &font_, const char *s, int len) { +	FLOAT width = 1.0;  	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); +	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 sz.cx; +	return int(width + 0.5);  } -void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positions) { +void SurfaceImpl::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); -		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; +	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); @@ -921,39 +1045,17 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi  		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); -			if (!::GetTextExtentExPointA(hdc, s, lenBlock, maxWidthMeasure, &fit, positions, &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; -			} -			startOffset = positions[lenBlock-1]; -			len -= lenBlock; -			positions += lenBlock; -			s += lenBlock; +	} 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 { -		// Support Asian string display in 9x English -		const TextWide tbuf(s, len, unicodeMode, codePage); -		TextPositions poses(tbuf.tlen); -		for (int widthSS=0; widthSS<tbuf.tlen; widthSS++) { -			::GetTextExtentPoint32W(hdc, tbuf.buffer, widthSS+1, &sz); -			poses.buffer[widthSS] = sz.cx; -		} +		// May be more than one byte per position  		int ui = 0;  		for (int i=0;i<len;) {  			if (::IsDBCSLeadByteEx(codePage, s[i])) { @@ -970,77 +1072,138 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi  	}  } -int SurfaceImpl::WidthChar(Font &font_, char ch) { +XYPOSITION SurfaceImpl::WidthChar(Font &font_, char ch) { +	FLOAT width = 1.0;  	SetFont(font_); -	SIZE sz; -	::GetTextExtentPoint32A(hdc, &ch, 1, &sz); -	return sz.cx; +	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);  } -int SurfaceImpl::Ascent(Font &font_) { +XYPOSITION SurfaceImpl::Ascent(Font &font_) { +	FLOAT ascent = 1.0;  	SetFont(font_); -	TEXTMETRIC tm; -	::GetTextMetrics(hdc, &tm); -	return tm.tmAscent; +	if (pIDWriteFactory && pTextFormat) { +		SetFont(font_); +		// Create a layout +		IDWriteTextLayout *pTextLayout = 0; +		HRESULT hr = pIDWriteFactory->CreateTextLayout(L"X", 1, pTextFormat, 1000.0, 1000.0, &pTextLayout); +		if (SUCCEEDED(hr)) { +			DWRITE_TEXT_METRICS textMetrics; +			pTextLayout->GetMetrics(&textMetrics); +			ascent = textMetrics.layoutHeight; +			const int clusters = 20; +			DWRITE_CLUSTER_METRICS clusterMetrics[clusters]; +			UINT32 count = 0; +			pTextLayout->GetClusterMetrics(clusterMetrics, clusters, &count); +			//height = pTextLayout->GetMaxHeight(); +			FLOAT minWidth = 0; +			hr = pTextLayout->DetermineMinWidth(&minWidth); +			const int maxLines = 2; +			DWRITE_LINE_METRICS lineMetrics[maxLines]; +			UINT32 lineCount = 0; +			hr = pTextLayout->GetLineMetrics(lineMetrics, maxLines, &lineCount); +			if (SUCCEEDED(hr)) { +				ascent = lineMetrics[0].baseline; +			} +			pTextLayout->Release(); +		} +	} +	return int(ascent + 0.5);  } -int SurfaceImpl::Descent(Font &font_) { +XYPOSITION SurfaceImpl::Descent(Font &font_) { +	FLOAT descent = 1.0;  	SetFont(font_); -	TEXTMETRIC tm; -	::GetTextMetrics(hdc, &tm); -	return tm.tmDescent; +	if (pIDWriteFactory && pTextFormat) { +		// Create a layout +		IDWriteTextLayout *pTextLayout = 0; +		HRESULT hr = pIDWriteFactory->CreateTextLayout(L"X", 1, pTextFormat, 1000.0, 1000.0, &pTextLayout); +		if (SUCCEEDED(hr)) { +			const int maxLines = 2; +			DWRITE_LINE_METRICS lineMetrics[maxLines]; +			UINT32 lineCount = 0; +			hr = pTextLayout->GetLineMetrics(lineMetrics, maxLines, &lineCount); +			if (SUCCEEDED(hr)) { +				descent = lineMetrics[0].height - lineMetrics[0].baseline; +			} +			pTextLayout->Release(); +		} +	} +	return int(descent + 0.5);  } -int SurfaceImpl::InternalLeading(Font &font_) { -	SetFont(font_); -	TEXTMETRIC tm; -	::GetTextMetrics(hdc, &tm); -	return tm.tmInternalLeading; +XYPOSITION SurfaceImpl::InternalLeading(Font &) { +	return 0;  } -int SurfaceImpl::ExternalLeading(Font &font_) { -	SetFont(font_); -	TEXTMETRIC tm; -	::GetTextMetrics(hdc, &tm); -	return tm.tmExternalLeading; +XYPOSITION SurfaceImpl::ExternalLeading(Font &) { +	return 1;  } -int SurfaceImpl::Height(Font &font_) { +XYPOSITION SurfaceImpl::Height(Font &font_) { +	FLOAT height = 1.0;  	SetFont(font_); -	TEXTMETRIC tm; -	::GetTextMetrics(hdc, &tm); -	return tm.tmHeight; +	if (pIDWriteFactory && pTextFormat) { +		// Create a layout +		IDWriteTextLayout *pTextLayout = 0; +		HRESULT hr = pIDWriteFactory->CreateTextLayout(L"X", 1, pTextFormat, 1000.0, 1000.0, &pTextLayout); +		if (SUCCEEDED(hr)) { +			const int maxLines = 2; +			DWRITE_LINE_METRICS lineMetrics[maxLines]; +			UINT32 lineCount = 0; +			hr = pTextLayout->GetLineMetrics(lineMetrics, maxLines, &lineCount); +			if (SUCCEEDED(hr)) { +				height = lineMetrics[0].height; +			} +			pTextLayout->Release(); +		} +	} +	// Truncating rather than rounding as otherwise too much space. +	return int(height);  } -int SurfaceImpl::AverageCharWidth(Font &font_) { +XYPOSITION SurfaceImpl::AverageCharWidth(Font &font_) { +	FLOAT width = 1.0;  	SetFont(font_); -	TEXTMETRIC tm; -	::GetTextMetrics(hdc, &tm); -	return tm.tmAveCharWidth; +	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 SurfaceImpl::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; +int SurfaceImpl::SetPalette(Palette *, bool) { +	return 0;  }  void SurfaceImpl::SetClip(PRectangle rc) { -	::IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom); +	if (pRenderTarget) { +		D2D1_RECT_F rcClip = {rc.left, rc.top, rc.right, rc.bottom}; +		pRenderTarget->PushAxisAlignedClip(rcClip, D2D1_ANTIALIAS_MODE_ALIASED); +		clipsActive++; +	}  }  void SurfaceImpl::FlushCachedState() { -	pen = 0; -	brush = 0; -	font = 0;  }  void SurfaceImpl::SetUnicodeMode(bool unicodeMode_) { @@ -1651,6 +1814,8 @@ void ListBoxX::Draw(DRAWITEMSTRUCT *pDrawItem) {  		if (pimage) {  			Surface *surfaceItem = Surface::Allocate();  			if (surfaceItem) { +				// TODO: Need a DC RenderTarget here +				/*  				surfaceItem->Init(pDrawItem->hDC, pDrawItem->hwndItem);  				int left = pDrawItem->rcItem.left + ItemInset.x + ImageInset.x;  				PRectangle rcImage(left, pDrawItem->rcItem.top, @@ -1658,6 +1823,7 @@ void ListBoxX::Draw(DRAWITEMSTRUCT *pDrawItem) {  				surfaceItem->DrawRGBAImage(rcImage,  					pimage->GetWidth(), pimage->GetHeight(), pimage->Pixels());  				delete surfaceItem; +				*/  				::SetTextAlign(pDrawItem->hDC, TA_TOP);  			}  		} | 
