aboutsummaryrefslogtreecommitdiffhomepage
path: root/win32
diff options
context:
space:
mode:
Diffstat (limited to 'win32')
-rw-r--r--win32/PlatWin.cxx884
-rw-r--r--win32/ScintillaWin.cxx118
2 files changed, 627 insertions, 375 deletions
diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx
index 6a2f103ba..2ba4ed374 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
@@ -264,7 +290,51 @@ FontCached::FontCached(const char *faceName_, int characterSet_, int size_, bool
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_;
+ HRESULT hr = pIDWriteFactory->CreateTextFormat(wszFace, NULL,
+ bold_ ? DWRITE_FONT_WEIGHT_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;
}
@@ -279,8 +349,7 @@ 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;
}
@@ -338,24 +407,13 @@ Font::~Font() {
void Font::Create(const char *faceName, int characterSet, int 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 +425,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 +454,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_);
@@ -441,14 +507,12 @@ 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) {
// 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 +521,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 +539,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 +651,156 @@ 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;
}
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(rc.left + 0.5, rc.top+0.5, 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(rc.left, rc.top, 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);
- }
-
- BLENDFUNCTION merge = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+ 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);
- 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 +808,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 +820,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.
@@ -794,62 +905,48 @@ public:
};
typedef VarBuffer<int, 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_, int 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);
+ } 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,
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,
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,
@@ -857,44 +954,63 @@ void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, con
// 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) {
+ 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) {
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);
}
}
+ 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 +1037,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])) {
@@ -971,76 +1065,137 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi
}
int 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_) {
+ 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_) {
+ 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;
+int SurfaceImpl::InternalLeading(Font &) {
+ return 0;
}
-int SurfaceImpl::ExternalLeading(Font &font_) {
- SetFont(font_);
- TEXTMETRIC tm;
- ::GetTextMetrics(hdc, &tm);
- return tm.tmExternalLeading;
+int SurfaceImpl::ExternalLeading(Font &) {
+ return 1;
}
int 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_) {
+ 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 +1806,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 +1815,7 @@ void ListBoxX::Draw(DRAWITEMSTRUCT *pDrawItem) {
surfaceItem->DrawRGBAImage(rcImage,
pimage->GetWidth(), pimage->GetHeight(), pimage->Pixels());
delete surfaceItem;
+ */
::SetTextAlign(pDrawItem->hDC, TA_TOP);
}
}
diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx
index 9925a64bb..28e48596b 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"
@@ -197,6 +200,10 @@ class ScintillaWin :
static HINSTANCE hInstance;
+ IDWriteFactory *pIDWriteFactory;
+ ID2D1Factory *pD2DFactory;
+ ID2D1HwndRenderTarget *pRenderTarget;
+
ScintillaWin(HWND hwnd);
ScintillaWin(const ScintillaWin &);
virtual ~ScintillaWin();
@@ -204,6 +211,8 @@ class ScintillaWin :
virtual void Initialise();
virtual void Finalise();
+ void EnsureRenderTarget();
+ void DropRenderTarget();
HWND MainHWND();
static sptr_t DirectFunction(
@@ -350,6 +359,10 @@ ScintillaWin::ScintillaWin(HWND hwnd) {
sysCaretWidth = 0;
sysCaretHeight = 0;
+ pIDWriteFactory = 0;
+ pD2DFactory = 0;
+ pRenderTarget = 0;
+
keysAlwaysUnicode = false;
caret.period = ::GetCaretBlinkTime();
@@ -378,18 +391,69 @@ void ScintillaWin::Initialise() {
::GetProcAddress(commctrl32, "_TrackMouseEvent");
}
}
+
+ if (!pIDWriteFactory) {
+ DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
+ __uuidof(IDWriteFactory),
+ reinterpret_cast<IUnknown**>(&pIDWriteFactory));
+ }
+ if (!pD2DFactory) {
+ D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory);
+ }
}
void ScintillaWin::Finalise() {
ScintillaBase::Finalise();
SetTicking(false);
SetIdle(false);
+ DropRenderTarget();
+ if (pIDWriteFactory) {
+ pIDWriteFactory->Release();
+ pIDWriteFactory = 0;
+ }
+ if (pD2DFactory) {
+ pD2DFactory->Release();
+ pD2DFactory = 0;
+ }
::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,8 +569,11 @@ LRESULT ScintillaWin::WndPaint(uptr_t wParam) {
pps = &ps;
::BeginPaint(MainHWND(), pps);
}
- AutoSurface surfaceWindow(pps->hdc, this);
+ //AutoSurface surfaceWindow(pps->hdc, this);
+ EnsureRenderTarget();
+ AutoSurface surfaceWindow(pRenderTarget, this);
if (surfaceWindow) {
+ pRenderTarget->BeginDraw();
rcPaint = PRectangle(pps->rcPaint.left, pps->rcPaint.top, pps->rcPaint.right, pps->rcPaint.bottom);
PRectangle rcClient = GetClientRectangle();
paintingAllText = rcPaint.Contains(rcClient);
@@ -517,6 +584,10 @@ LRESULT ScintillaWin::WndPaint(uptr_t wParam) {
}
Paint(surfaceWindow, rcPaint);
surfaceWindow->Release();
+ HRESULT hr = pRenderTarget->EndDraw();
+ if (hr == D2DERR_RECREATE_TARGET) {
+ DropRenderTarget();
+ }
}
if (hRgnUpdate) {
::DeleteRgn(hRgnUpdate);
@@ -674,6 +745,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();
}
@@ -1189,11 +1261,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() {
@@ -2283,7 +2356,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
@@ -2296,6 +2371,7 @@ void ScintillaWin::RealizeWindowPalette(bool inBackGround) {
surfaceWindow->Release();
}
::ReleaseDC(MainHWND(), hdc);
+*/
}
/**
@@ -2303,23 +2379,30 @@ void ScintillaWin::RealizeWindowPalette(bool inBackGround) {
* This paint will not be abandoned.
*/
void ScintillaWin::FullPaint() {
- HDC hdc = ::GetDC(MainHWND());
- FullPaintDC(hdc);
- ::ReleaseDC(MainHWND(), hdc);
+ //HDC hdc = ::GetDC(MainHWND());
+ //FullPaintDC(hdc);
+ //::ReleaseDC(MainHWND(), hdc);
+ FullPaintDC(0);
}
/**
* Redraw all of text area on the specified DC.
* This paint will not be abandoned.
*/
-void ScintillaWin::FullPaintDC(HDC hdc) {
+void ScintillaWin::FullPaintDC(HDC) {
paintState = painting;
rcPaint = GetClientRectangle();
paintingAllText = true;
- AutoSurface surfaceWindow(hdc, this);
+ 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;
}
@@ -2693,10 +2776,21 @@ sptr_t PASCAL ScintillaWin::CTWndProc(
::BeginPaint(hWnd, &ps);
Surface *surfaceWindow = Surface::Allocate();
if (surfaceWindow) {
- surfaceWindow->Init(ps.hdc, hWnd);
+ ID2D1HwndRenderTarget *pCTRenderTarget = 0;
+ RECT rc;
+ GetClientRect(hWnd, &rc);
+ // Create a Direct2D render target.
+ sciThis->pD2DFactory->CreateHwndRenderTarget(
+ D2D1::RenderTargetProperties(),
+ D2D1::HwndRenderTargetProperties(hWnd, D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)),
+ &pCTRenderTarget);
+ //surfaceWindow->Init(ps.hdc, hWnd);
+ surfaceWindow->Init(pCTRenderTarget, hWnd);
surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == sciThis->ct.codePage);
surfaceWindow->SetDBCSMode(sciThis->ct.codePage);
+ pCTRenderTarget->BeginDraw();
sciThis->ct.PaintCT(surfaceWindow);
+ pCTRenderTarget->EndDraw();
surfaceWindow->Release();
delete surfaceWindow;
}