From 6ef96951cabf9de853f7b40a9924c0f442e8fb50 Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Mon, 1 Aug 2011 19:13:04 +1000 Subject: Experimental Direct2D and DirectWrite platform layer. --- win32/PlatWin.cxx | 884 +++++++++++++++++++++++++++++-------------------- win32/ScintillaWin.cxx | 118 ++++++- 2 files changed, 627 insertions(+), 375 deletions(-) (limited to 'win32') 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 #include #include +#include +#include #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(&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(::SelectObject(hdc, font_.GetID())); + DWORD sizeOLTM = ::GetOutlineTextMetrics(hdc, NULL, NULL); + std::vector vOLTM(sizeOLTM); + LPOUTLINETEXTMETRIC potm = reinterpret_cast(&vOLTM[0]); + DWORD worked = ::GetOutlineTextMetrics(hdc, sizeOLTM, potm); + ::SelectObject(hdc, fontSave); + if (!worked) + return; + const WCHAR *pwcFamily = reinterpret_cast(&vOLTM[reinterpret_cast(potm->otmpFamilyName)]); + //const WCHAR *pwcFace = reinterpret_cast(&vOLTM[reinterpret_cast(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(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(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), penOld); - ::DeleteObject(pen); - penOld = 0; - } - pen = 0; - if (brushOld) { - ::SelectObject(reinterpret_cast(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), fontOld); - fontOld = 0; - } - font = 0; - if (bitmapOld) { - ::SelectObject(reinterpret_cast(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), - reinterpret_cast(paletteOld), TRUE); - paletteOld = 0; - } if (hdcOwned) { ::DeleteDC(reinterpret_cast(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), TA_BASELINE); + RECT rc; + ::GetClientRect(reinterpret_cast(wid), &rc); + SetDWrite(hdc); } void SurfaceImpl::Init(SurfaceID sid, WindowID) { Release(); - hdc = reinterpret_cast(sid); + hdc = ::CreateCompatibleDC(NULL); + hdcOwned = true; + pRenderTarget = reinterpret_cast(sid); ::SetTextAlign(reinterpret_cast(hdc), TA_BASELINE); + SetDWrite(hdc); } void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID) { Release(); - hdc = ::CreateCompatibleDC(static_cast(surface_)->hdc); + hdc = ::CreateCompatibleDC(NULL); // Just for measurement hdcOwned = true; - bitmap = ::CreateCompatibleBitmap(static_cast(surface_)->hdc, width, height); - bitmapOld = static_cast(::SelectObject(hdc, bitmap)); - ::SetTextAlign(reinterpret_cast(hdc), TA_BASELINE); -} - -void SurfaceImpl::PenColour(ColourAllocated fore) { - if (pen) { - ::SelectObject(hdc, penOld); - ::DeleteObject(pen); - pen = 0; - penOld = 0; + SurfaceImpl *psurfOther = static_cast(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(::SelectObject(reinterpret_cast(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(::SelectObject(hdc, brush)); } void SurfaceImpl::SetFont(Font &font_) { - if (font_.GetID() != font) { - if (fontOld) { - ::SelectObject(hdc, font_.GetID()); - } else { - fontOld = static_cast(::SelectObject(hdc, font_.GetID())); - } - font = reinterpret_cast(font_.GetID()); - } + FormatAndBaseline *pfabl = reinterpret_cast(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(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(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(surfacePattern).bitmap) - br = ::CreatePatternBrush(static_cast(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(surfacePattern); + surfOther.FlushDrawing(); + ID2D1Bitmap *pBitmap = NULL; + ID2D1BitmapRenderTarget *pCompatibleRenderTarget = reinterpret_cast( + 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)); - 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(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(GetBValue(fill.AsLong()) * alphaFill / 255), - static_cast(GetGValue(fill.AsLong()) * alphaFill / 255), - static_cast(GetRValue(fill.AsLong()) * alphaFill / 255), - static_cast(alphaFill)); - DWORD valOutline = dwordFromBGRA( - static_cast(GetBValue(outline.AsLong()) * alphaOutline / 255), - static_cast(GetGValue(outline.AsLong()) * alphaOutline / 255), - static_cast(GetRValue(outline.AsLong()) * alphaOutline / 255), - static_cast(alphaOutline)); - DWORD *pixels = reinterpret_cast(image); - for (int y=0; yFillRoundedRectangle(roundedRectFill, pBrush); - AlphaBlendFn(reinterpret_cast(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)); + 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(hMemDC), &bpih, - DIB_RGB_COLORS, reinterpret_cast(&image), NULL, 0); - HBITMAP hbmOld = SelectBitmap(hMemDC, hbmMem); - - for (int y=height-1; y>=0; y--) { + std::vector image(height * width * 4); + for (int y=0; y(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(surfaceSource).hdc, from.x, from.y, SRCCOPY); + SurfaceImpl &surfOther = static_cast(surfaceSource); + surfOther.FlushDrawing(); + ID2D1BitmapRenderTarget *pCompatibleRenderTarget = reinterpret_cast( + 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 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(rcw.left) / dpiScaleX, + static_cast(ybase-baseline) / dpiScaleY, + static_cast(rcw.right + 1) / dpiScaleX, + static_cast(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;iCreateTextLayout(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(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(s); @@ -921,39 +1037,17 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi while (i 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 0) { - for (int i=0;i(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; widthSSCreateTextLayout(&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(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 #include +#include +#include + #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(&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(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; } -- cgit v1.2.3 From c4ba4ab013dc711f9caa5521b635b68f92a87e33 Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Tue, 2 Aug 2011 11:24:48 +1000 Subject: Allow floating point text positioning. --- win32/PlatWin.cxx | 81 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 38 deletions(-) (limited to 'win32') diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index 2ba4ed374..d4a015cf9 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -273,20 +273,20 @@ 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_); @@ -338,7 +338,7 @@ FontCached::FontCached(const char *faceName_, int characterSet_, int size_, bool 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)) && @@ -353,7 +353,7 @@ void FontCached::Release() { 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_); @@ -404,7 +404,7 @@ 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(); if (faceName) @@ -481,19 +481,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); @@ -664,6 +664,10 @@ static int Delta(int difference) { return 0; } +static int RoundFloat(float f) { + return int(f+0.5); +} + void SurfaceImpl::LineTo(int x_, int y_) { if (pRenderTarget) { int xDiff = x_ - x; @@ -726,7 +730,7 @@ void SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllo void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) { 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); + 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); @@ -737,7 +741,7 @@ void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAlloc void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) { if (pRenderTarget) { D2DPenColour(back); - D2D1_RECT_F rectangle1 = D2D1::RectF(rc.left, rc.top, rc.right, rc.bottom); + D2D1_RECT_F rectangle1 = D2D1::RectF(RoundFloat(rc.left), rc.top, RoundFloat(rc.right), rc.bottom); pRenderTarget->FillRectangle(&rectangle1, pBrush); } } @@ -903,9 +907,9 @@ public: } } }; -typedef VarBuffer TextPositions; +typedef VarBuffer TextPositions; -void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, int ybase, const char *s, int len, UINT) { +void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT) { SetFont(font_); RECT rcw = RectFromPRectangle(rc); @@ -919,7 +923,7 @@ void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, int ybase, const ch rc.Width()+2, rc.Height(), &pTextLayout); if (SUCCEEDED(hr)) { D2D1_POINT_2F origin = {rc.left, ybase-baseline}; - pRenderTarget->DrawTextLayout(origin, pTextLayout, pBrush); + pRenderTarget->DrawTextLayout(origin, pTextLayout, pBrush, D2D1_DRAW_TEXT_OPTIONS_NONE); } else { D2D1_RECT_F layoutRect = D2D1::RectF( static_cast(rcw.left) / dpiScaleX, @@ -931,7 +935,7 @@ 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 SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back) { if (pRenderTarget) { FillRectangle(rc, back); @@ -940,7 +944,7 @@ void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const ch } } -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) { if (pRenderTarget) { FillRectangle(rc, back); @@ -949,7 +953,7 @@ void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, int ybase, const c } } -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(tbuf.tlen)); @@ -1064,7 +1069,7 @@ 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_); if (pIDWriteFactory && pTextFormat) { @@ -1082,7 +1087,7 @@ int SurfaceImpl::WidthChar(Font &font_, char ch) { return int(width + 0.5); } -int SurfaceImpl::Ascent(Font &font_) { +XYPOSITION SurfaceImpl::Ascent(Font &font_) { FLOAT ascent = 1.0; SetFont(font_); if (pIDWriteFactory && pTextFormat) { @@ -1114,7 +1119,7 @@ int SurfaceImpl::Ascent(Font &font_) { return int(ascent + 0.5); } -int SurfaceImpl::Descent(Font &font_) { +XYPOSITION SurfaceImpl::Descent(Font &font_) { FLOAT descent = 1.0; SetFont(font_); if (pIDWriteFactory && pTextFormat) { @@ -1135,15 +1140,15 @@ int SurfaceImpl::Descent(Font &font_) { return int(descent + 0.5); } -int SurfaceImpl::InternalLeading(Font &) { +XYPOSITION SurfaceImpl::InternalLeading(Font &) { return 0; } -int SurfaceImpl::ExternalLeading(Font &) { +XYPOSITION SurfaceImpl::ExternalLeading(Font &) { return 1; } -int SurfaceImpl::Height(Font &font_) { +XYPOSITION SurfaceImpl::Height(Font &font_) { FLOAT height = 1.0; SetFont(font_); if (pIDWriteFactory && pTextFormat) { @@ -1165,7 +1170,7 @@ int SurfaceImpl::Height(Font &font_) { return int(height); } -int SurfaceImpl::AverageCharWidth(Font &font_) { +XYPOSITION SurfaceImpl::AverageCharWidth(Font &font_) { FLOAT width = 1.0; SetFont(font_); if (pIDWriteFactory && pTextFormat) { -- cgit v1.2.3 From 32ccf7ecf4286b9ce64360c1c857f743cbcf51f4 Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Tue, 2 Aug 2011 13:22:10 +1000 Subject: Use SEMI_BOLD for bold as Segoe UI looks better at semi bold than bold. Allow fractional font sizes by multiplying by 1000. --- win32/PlatWin.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'win32') diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index d4a015cf9..9e9ead409 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -313,8 +313,10 @@ FontCached::FontCached(const char *faceName_, int characterSet_, float size_, bo 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_BOLD : DWRITE_FONT_WEIGHT_REGULAR, + 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)) { -- cgit v1.2.3 From c01c7f0cab76fb3e4a43801a405e68e68cc08629 Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Wed, 3 Aug 2011 11:19:33 +1000 Subject: Fixed some warnings. --- win32/PlatWin.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'win32') diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index 9e9ead409..acbb5f62d 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -514,7 +514,8 @@ public: SurfaceImpl::SurfaceImpl() : unicodeMode(false), - hdc(0), hdcOwned(false) { + 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 -- cgit v1.2.3 From b510d1fe619eff95c7e0d0a88421b8e3cad8f729 Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Sun, 7 Aug 2011 13:41:35 +1000 Subject: Implement APIs for fractional font sizes and a range of weights. --- win32/PlatWin.cxx | 57 +++++++++++++++++++++++++------------------------- win32/ScintillaWin.cxx | 8 +++---- 2 files changed, 33 insertions(+), 32 deletions(-) (limited to 'win32') diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index acbb5f62d..b22cd10a1 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -242,11 +242,13 @@ static BYTE Win32MapFontQuality(int extraFontFlag) { } } -static void SetLogFont(LOGFONTA &lf, const char *faceName, int characterSet, int size, bool bold, bool italic, int extraFontFlag) { +const int fontSizeMultiplier = 100; + +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(size/fontSizeMultiplier))); + lf.lfWeight = weight; lf.lfItalic = static_cast(italic ? 1 : 0); lf.lfCharSet = static_cast(characterSet); lf.lfQuality = Win32MapFontQuality(extraFontFlag); @@ -258,12 +260,12 @@ 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 char *faceName, int characterSet, float size, int weight, bool italic, int extraFontFlag) { return - size ^ + static_cast((size / fontSizeMultiplier)) ^ (characterSet << 10) ^ ((extraFontFlag & SC_EFF_QUALITY_MASK) << 9) ^ - (bold ? 0x10000000 : 0) ^ + ((weight/100) << 12) ^ (italic ? 0x20000000 : 0) ^ faceName[0]; } @@ -271,25 +273,26 @@ static int HashFont(const char *faceName, int characterSet, int size, bool bold, class FontCached : Font { FontCached *next; int usage; + float size; LOGFONTA lf; int hash; - FontCached(const char *faceName_, int characterSet_, float size_, bool bold_, bool italic_, int extraFontFlag_); + FontCached(const char *faceName_, int characterSet_, float size_, int weight_, bool italic_, int extraFontFlag_); ~FontCached() {} - bool SameAs(const char *faceName_, int characterSet_, float size_, bool bold_, bool italic_, int extraFontFlag_); + bool SameAs(const char *faceName_, int characterSet_, float size_, int weight_, bool italic_, int extraFontFlag_); virtual void Release(); static FontCached *first; public: - static FontID FindOrCreate(const char *faceName_, int characterSet_, float size_, bool bold_, bool italic_, int extraFontFlag_); + static FontID FindOrCreate(const char *faceName_, int characterSet_, float size_, int weight_, bool italic_, int extraFontFlag_); static void ReleaseId(FontID fid_); }; FontCached *FontCached::first = 0; -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_); +FontCached::FontCached(const char *faceName_, int characterSet_, float size_, int weight_, bool italic_, int extraFontFlag_) : + next(0), usage(0), size(1.0), hash(0) { + SetLogFont(lf, faceName_, characterSet_, size_, weight_, italic_, extraFontFlag_); + hash = HashFont(faceName_, characterSet_, size_, weight_, italic_, extraFontFlag_); fid = 0; EnsureDWriteFactory(); if (pIDWriteFactory) { @@ -312,11 +315,9 @@ FontCached::FontCached(const char *faceName_, int characterSet_, float size_, bo const int faceSize = 200; WCHAR wszFace[faceSize]; UTF16FromUTF8(faceName_, strlen(faceName_)+1, wszFace, faceSize); - FLOAT fHeight = size_; - if (fHeight > 2000) - fHeight = fHeight / 1000.0f; + FLOAT fHeight = size_ / fontSizeMultiplier; HRESULT hr = pIDWriteFactory->CreateTextFormat(wszFace, NULL, - bold_ ? DWRITE_FONT_WEIGHT_SEMI_BOLD : DWRITE_FONT_WEIGHT_REGULAR, + static_cast(weight_), italic_ ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, fHeight, L"en-us", &pTextFormat); if (SUCCEEDED(hr)) { @@ -325,7 +326,7 @@ FontCached::FontCached(const char *faceName_, int characterSet_, float size_, bo UINT32 lineCount = 0; FLOAT baseline = 1.0f; IDWriteTextLayout *pTextLayout = 0; - HRESULT hr = pIDWriteFactory->CreateTextLayout(L"X", 1, pTextFormat, + hr = pIDWriteFactory->CreateTextLayout(L"X", 1, pTextFormat, 100.0f, 100.0f, &pTextLayout); if (SUCCEEDED(hr)) { hr = pTextLayout->GetLineMetrics(lineMetrics, maxLines, &lineCount); @@ -340,10 +341,10 @@ FontCached::FontCached(const char *faceName_, int characterSet_, float size_, bo usage = 1; } -bool FontCached::SameAs(const char *faceName_, int characterSet_, float size_, bool bold_, bool italic_, int extraFontFlag_) { +bool FontCached::SameAs(const char *faceName_, int characterSet_, float size_, int weight_, bool italic_, int extraFontFlag_) { return - (lf.lfHeight == -(abs(size_))) && - (lf.lfWeight == (bold_ ? FW_BOLD : FW_NORMAL)) && + (size == size_) && + (lf.lfWeight == weight_) && (lf.lfItalic == static_cast(italic_ ? 1 : 0)) && (lf.lfCharSet == characterSet_) && (lf.lfQuality == Win32MapFontQuality(extraFontFlag_)) && @@ -355,19 +356,19 @@ void FontCached::Release() { fid = 0; } -FontID FontCached::FindOrCreate(const char *faceName_, int characterSet_, float size_, bool bold_, bool italic_, int extraFontFlag_) { +FontID FontCached::FindOrCreate(const char *faceName_, int characterSet_, float size_, int weight_, bool italic_, int extraFontFlag_) { FontID ret = 0; ::EnterCriticalSection(&crPlatformLock); - int hashFind = HashFont(faceName_, characterSet_, size_, bold_, italic_, extraFontFlag_); + int hashFind = HashFont(faceName_, characterSet_, size_, weight_, italic_, extraFontFlag_); for (FontCached *cur=first; cur; cur=cur->next) { if ((cur->hash == hashFind) && - cur->SameAs(faceName_, characterSet_, size_, bold_, italic_, extraFontFlag_)) { + cur->SameAs(faceName_, characterSet_, size_, weight_, italic_, extraFontFlag_)) { cur->usage++; ret = cur->fid; } } if (ret == 0) { - FontCached *fc = new FontCached(faceName_, characterSet_, size_, bold_, italic_, extraFontFlag_); + FontCached *fc = new FontCached(faceName_, characterSet_, size_, weight_, italic_, extraFontFlag_); if (fc) { fc->next = first; first = fc; @@ -407,10 +408,10 @@ Font::~Font() { #define FONTS_CACHED void Font::Create(const char *faceName, int characterSet, float size, - bool bold, bool italic, int extraFontFlag) { + int weight, bool italic, int extraFontFlag) { Release(); if (faceName) - fid = FontCached::FindOrCreate(faceName, characterSet, size, bold, italic, extraFontFlag); + fid = FontCached::FindOrCreate(faceName, characterSet, size, weight, italic, extraFontFlag); } void Font::Release() { @@ -515,7 +516,7 @@ public: SurfaceImpl::SurfaceImpl() : unicodeMode(false), hdc(0), hdcOwned(false), - x(0), y(0), { + 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 diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index 28e48596b..6bc770eed 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -2151,9 +2151,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) { @@ -2161,7 +2161,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(vs.styles[styleHere].italic ? 1 : 0); lf.lfCharSet = DEFAULT_CHARSET; lf.lfFaceName[0] = '\0'; -- cgit v1.2.3 From 113e4a09052842f129114abc7350f72401cd1198 Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Sun, 7 Aug 2011 14:18:37 +1000 Subject: Move scaling of font to pixels up into platform-independent code. --- win32/PlatWin.cxx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'win32') diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index b22cd10a1..b0fbd2543 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -242,12 +242,10 @@ static BYTE Win32MapFontQuality(int extraFontFlag) { } } -const int fontSizeMultiplier = 100; - 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(static_cast(size/fontSizeMultiplier))); + lf.lfHeight = -(abs(static_cast(size))); lf.lfWeight = weight; lf.lfItalic = static_cast(italic ? 1 : 0); lf.lfCharSet = static_cast(characterSet); @@ -262,7 +260,7 @@ static void SetLogFont(LOGFONTA &lf, const char *faceName, int characterSet, flo */ static int HashFont(const char *faceName, int characterSet, float size, int weight, bool italic, int extraFontFlag) { return - static_cast((size / fontSizeMultiplier)) ^ + static_cast(size) ^ (characterSet << 10) ^ ((extraFontFlag & SC_EFF_QUALITY_MASK) << 9) ^ ((weight/100) << 12) ^ @@ -315,7 +313,7 @@ FontCached::FontCached(const char *faceName_, int characterSet_, float size_, in const int faceSize = 200; WCHAR wszFace[faceSize]; UTF16FromUTF8(faceName_, strlen(faceName_)+1, wszFace, faceSize); - FLOAT fHeight = size_ / fontSizeMultiplier; + FLOAT fHeight = size_; HRESULT hr = pIDWriteFactory->CreateTextFormat(wszFace, NULL, static_cast(weight_), italic_ ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, -- cgit v1.2.3 From 76cc7d2f163f6be5ad56aa496d5c24c8828ed3f5 Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Sun, 7 Aug 2011 21:28:48 +1000 Subject: Dynamically loading Direct2D and DirectWrite at run time so can run on Windows XP. --- win32/PlatWin.cxx | 51 ++++++++++++++++++++++++++++++++++---------------- win32/PlatWin.h | 13 +++++++++++++ win32/ScintillaWin.cxx | 29 +++------------------------- 3 files changed, 51 insertions(+), 42 deletions(-) create mode 100644 win32/PlatWin.h (limited to 'win32') diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index b0fbd2543..a1ae68b82 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -197,15 +197,42 @@ void Palette::Allocate(Window &) { } } -static IDWriteFactory *pIDWriteFactory = 0; - -static void EnsureDWriteFactory() { - // Construct - if (!pIDWriteFactory) { - DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, - __uuidof(IDWriteFactory), - reinterpret_cast(&pIDWriteFactory)); +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(&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(&pIDWriteFactory)); + } + } } + triedLoadingD2D = true; + return pIDWriteFactory && pD2DFactory; } struct FormatAndBaseline { @@ -292,7 +319,6 @@ FontCached::FontCached(const char *faceName_, int characterSet_, float size_, in SetLogFont(lf, faceName_, characterSet_, size_, weight_, italic_, extraFontFlag_); hash = HashFont(faceName_, characterSet_, size_, weight_, italic_, extraFontFlag_); fid = 0; - EnsureDWriteFactory(); if (pIDWriteFactory) { #ifdef OLD_CODE HFONT fontSave = static_cast(::SelectObject(hdc, font_.GetID())); @@ -508,9 +534,6 @@ public: } //namespace Scintilla #endif -#pragma comment(lib, "d2d1.lib") -#pragma comment(lib, "dwrite.lib") - SurfaceImpl::SurfaceImpl() : unicodeMode(false), hdc(0), hdcOwned(false), @@ -563,11 +586,7 @@ void SurfaceImpl::Release() { } } -// 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; } 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 +// 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 6bc770eed..f49b2bace 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -57,6 +57,7 @@ #include "Editor.h" #include "ScintillaBase.h" #include "UniConversion.h" +#include "PlatWin.h" #ifdef SCI_LEXER #include "ExternalLexer.h" @@ -90,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. @@ -200,8 +196,6 @@ class ScintillaWin : static HINSTANCE hInstance; - IDWriteFactory *pIDWriteFactory; - ID2D1Factory *pD2DFactory; ID2D1HwndRenderTarget *pRenderTarget; ScintillaWin(HWND hwnd); @@ -359,8 +353,6 @@ ScintillaWin::ScintillaWin(HWND hwnd) { sysCaretWidth = 0; sysCaretHeight = 0; - pIDWriteFactory = 0; - pD2DFactory = 0; pRenderTarget = 0; keysAlwaysUnicode = false; @@ -392,14 +384,7 @@ void ScintillaWin::Initialise() { } } - if (!pIDWriteFactory) { - DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, - __uuidof(IDWriteFactory), - reinterpret_cast(&pIDWriteFactory)); - } - if (!pD2DFactory) { - D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory); - } + LoadD2D(); } void ScintillaWin::Finalise() { @@ -407,14 +392,6 @@ void ScintillaWin::Finalise() { SetTicking(false); SetIdle(false); DropRenderTarget(); - if (pIDWriteFactory) { - pIDWriteFactory->Release(); - pIDWriteFactory = 0; - } - if (pD2DFactory) { - pD2DFactory->Release(); - pD2DFactory = 0; - } ::RevokeDragDrop(MainHWND()); if (SUCCEEDED(hrOle)) { ::OleUninitialize(); @@ -2780,7 +2757,7 @@ sptr_t PASCAL ScintillaWin::CTWndProc( RECT rc; GetClientRect(hWnd, &rc); // Create a Direct2D render target. - sciThis->pD2DFactory->CreateHwndRenderTarget( + pD2DFactory->CreateHwndRenderTarget( D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties(hWnd, D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)), &pCTRenderTarget); -- cgit v1.2.3 From eeff5b85a911ec3d68160bf7df603994afcb61c7 Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Sun, 7 Aug 2011 21:44:33 +1000 Subject: Remove unused field. --- win32/PlatWin.cxx | 3 --- 1 file changed, 3 deletions(-) (limited to 'win32') diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index a1ae68b82..6e1f3f3be 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -462,7 +462,6 @@ class SurfaceImpl : public Surface { ID2D1RenderTarget *pRenderTarget; bool ownRenderTarget; - bool needsEndDraw; int clipsActive; IDWriteTextFormat *pTextFormat; @@ -549,7 +548,6 @@ SurfaceImpl::SurfaceImpl() : pRenderTarget = NULL; ownRenderTarget = false; - needsEndDraw = false; clipsActive = 0; pTextFormat = NULL; baseline = 1.0f; @@ -630,7 +628,6 @@ void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID) pRenderTarget = pCompatibleRenderTarget; pRenderTarget->BeginDraw(); ownRenderTarget = true; - needsEndDraw = true; } } -- cgit v1.2.3 From 65b8d104af351c0a5be2c62ad843dad8362ad8eb Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Sun, 7 Aug 2011 21:55:07 +1000 Subject: Ensure deallocation. --- win32/ScintillaWin.cxx | 1 + 1 file changed, 1 insertion(+) (limited to 'win32') diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index f49b2bace..28a630246 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -2770,6 +2770,7 @@ sptr_t PASCAL ScintillaWin::CTWndProc( pCTRenderTarget->EndDraw(); surfaceWindow->Release(); delete surfaceWindow; + pCTRenderTarget->Release(); } ::EndPaint(hWnd, &ps); return 0; -- cgit v1.2.3 From a6467fc29df6984d1ebd1a434214f4f23653e4d5 Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Sun, 7 Aug 2011 23:01:57 +1000 Subject: Autocompletion lists work with Direct2D. --- win32/PlatWin.cxx | 80 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 20 deletions(-) (limited to 'win32') diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index 6e1f3f3be..fdfd44d79 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -246,8 +246,25 @@ struct FormatAndBaseline { pTextFormat = 0; baseline = 1; } + HFONT HFont(); }; +HFONT FormatAndBaseline::HFont() { + LOGFONTW lf; + memset(&lf, 0, sizeof(lf)); + const int familySize = 200; + WCHAR fontFamilyName[familySize]; + + HRESULT hr = pTextFormat->GetFontFamilyName(fontFamilyName, familySize); + if (SUCCEEDED(hr)) { + lf.lfWeight = pTextFormat->GetFontWeight(); + lf.lfItalic = pTextFormat->GetFontStyle() == DWRITE_FONT_STYLE_ITALIC; + lf.lfHeight = -static_cast(pTextFormat->GetFontSize()); + return ::CreateFontIndirect(&lf); + } + return 0; +} + #ifndef CLEARTYPE_QUALITY #define CLEARTYPE_QUALITY 5 #endif @@ -1270,8 +1287,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); @@ -1648,17 +1664,19 @@ void ListBoxX::Create(Window &parent_, int ctrlID_, Point location_, int lineHei hinstanceParent, this); - ::MapWindowPoints(hwndParent, NULL, reinterpret_cast(&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); + FormatAndBaseline *pfabl = reinterpret_cast(font.GetID()); + fontCopy = pfabl->HFont(); ::SendMessage(lb, WM_SETFONT, reinterpret_cast(fontCopy), 0); } } @@ -1829,17 +1847,36 @@ 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, - left + images.GetWidth(), pDrawItem->rcItem.bottom); - surfaceItem->DrawRGBAImage(rcImage, - pimage->GetWidth(), pimage->GetHeight(), pimage->Pixels()); - delete surfaceItem; - */ - ::SetTextAlign(pDrawItem->hDC, TA_TOP); + if (pD2DFactory) { + 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; + ::SetTextAlign(pDrawItem->hDC, TA_TOP); + pDCRT->EndDraw(); + pDCRT->Release(); + } + } } } } @@ -1906,7 +1943,9 @@ void ListBoxX::SetList(const char *list, char separator, char typesep) { } void ListBoxX::AdjustWindowRect(PRectangle *rc) const { - ::AdjustWindowRectEx(reinterpret_cast(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 { @@ -1947,8 +1986,9 @@ void ListBoxX::SetRedraw(bool on) { void ListBoxX::ResizeToCursor() { PRectangle rc = GetPosition(); - Point pt; - ::GetCursorPos(reinterpret_cast(&pt)); + POINT ptw; + ::GetCursorPos(&ptw); + Point pt(ptw.x, ptw.y); pt.x += dragOffset.x; pt.y += dragOffset.y; -- cgit v1.2.3 From 13d3781cbaebe09a009ad7e3cbf909ed096c2a9e Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Mon, 8 Aug 2011 11:38:28 +1000 Subject: Make compile in narrow mode. --- win32/PlatWin.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'win32') diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index fdfd44d79..804fd66e1 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -260,7 +260,7 @@ HFONT FormatAndBaseline::HFont() { lf.lfWeight = pTextFormat->GetFontWeight(); lf.lfItalic = pTextFormat->GetFontStyle() == DWRITE_FONT_STYLE_ITALIC; lf.lfHeight = -static_cast(pTextFormat->GetFontSize()); - return ::CreateFontIndirect(&lf); + return ::CreateFontIndirectW(&lf); } return 0; } -- cgit v1.2.3 From efbc9a56b462a5085106c2a558e46a415a588664 Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Mon, 8 Aug 2011 11:42:22 +1000 Subject: Removed old code. --- win32/PlatWin.cxx | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'win32') diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index 804fd66e1..13a1de70d 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -337,21 +337,6 @@ FontCached::FontCached(const char *faceName_, int characterSet_, float size_, in hash = HashFont(faceName_, characterSet_, size_, weight_, italic_, extraFontFlag_); fid = 0; if (pIDWriteFactory) { -#ifdef OLD_CODE - HFONT fontSave = static_cast(::SelectObject(hdc, font_.GetID())); - DWORD sizeOLTM = ::GetOutlineTextMetrics(hdc, NULL, NULL); - std::vector vOLTM(sizeOLTM); - LPOUTLINETEXTMETRIC potm = reinterpret_cast(&vOLTM[0]); - DWORD worked = ::GetOutlineTextMetrics(hdc, sizeOLTM, potm); - ::SelectObject(hdc, fontSave); - if (!worked) - return; - const WCHAR *pwcFamily = reinterpret_cast(&vOLTM[reinterpret_cast(potm->otmpFamilyName)]); - //const WCHAR *pwcFace = reinterpret_cast(&vOLTM[reinterpret_cast(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]; -- cgit v1.2.3 From 6d2d631beea2548f47b03d9e07d690c1fb5bc636 Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Wed, 10 Aug 2011 10:41:03 +1000 Subject: Using safe sizes for ascent and descent which work for tallest characters. Fix HFONT conversion for use in autocompletion lists. --- win32/PlatWin.cxx | 124 ++++++++++++++++-------------------------------------- 1 file changed, 37 insertions(+), 87 deletions(-) (limited to 'win32') diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index 13a1de70d..5726e6fb2 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -235,27 +235,27 @@ bool LoadD2D() { return pIDWriteFactory && pD2DFactory; } -struct FormatAndBaseline { +struct FormatAndMetrics { IDWriteTextFormat *pTextFormat; - FLOAT baseline; - FormatAndBaseline(IDWriteTextFormat *pTextFormat_, FLOAT baseline_) : - pTextFormat(pTextFormat_), baseline(baseline_) { + FLOAT yAscent; + FLOAT yDescent; + FormatAndMetrics(IDWriteTextFormat *pTextFormat_, FLOAT yAscent_, FLOAT yDescent_) : + pTextFormat(pTextFormat_), yAscent(yAscent_), yDescent(yDescent_) { } - ~FormatAndBaseline() { + ~FormatAndMetrics() { pTextFormat->Release(); pTextFormat = 0; - baseline = 1; + yAscent = 2; + yDescent = 1; } HFONT HFont(); }; -HFONT FormatAndBaseline::HFont() { +HFONT FormatAndMetrics::HFont() { LOGFONTW lf; memset(&lf, 0, sizeof(lf)); - const int familySize = 200; - WCHAR fontFamilyName[familySize]; - HRESULT hr = pTextFormat->GetFontFamilyName(fontFamilyName, familySize); + HRESULT hr = pTextFormat->GetFontFamilyName(lf.lfFaceName, LF_FACESIZE); if (SUCCEEDED(hr)) { lf.lfWeight = pTextFormat->GetFontWeight(); lf.lfItalic = pTextFormat->GetFontStyle() == DWRITE_FONT_STYLE_ITALIC; @@ -342,26 +342,31 @@ FontCached::FontCached(const char *faceName_, int characterSet_, float size_, in WCHAR wszFace[faceSize]; UTF16FromUTF8(faceName_, strlen(faceName_)+1, wszFace, faceSize); FLOAT fHeight = size_; + DWRITE_FONT_STYLE style = italic_ ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; HRESULT hr = pIDWriteFactory->CreateTextFormat(wszFace, NULL, static_cast(weight_), - italic_ ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, + 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 baseline = 1.0f; + 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)) { - baseline = lineMetrics[0].baseline; + yAscent = lineMetrics[0].baseline; + yDescent = lineMetrics[0].height - lineMetrics[0].baseline; } pTextLayout->Release(); } - fid = reinterpret_cast(new FormatAndBaseline(pTextFormat, baseline)); + fid = reinterpret_cast(new FormatAndMetrics(pTextFormat, yAscent, yDescent)); } } usage = 1; @@ -378,7 +383,7 @@ bool FontCached::SameAs(const char *faceName_, int characterSet_, float size_, i } void FontCached::Release() { - delete reinterpret_cast(fid); + delete reinterpret_cast(fid); fid = 0; } @@ -467,7 +472,9 @@ class SurfaceImpl : public Surface { int clipsActive; IDWriteTextFormat *pTextFormat; - FLOAT baseline; + FLOAT yAscent; + FLOAT yDescent; + ID2D1SolidColorBrush *pBrush; float dpiScaleX; float dpiScaleY; @@ -552,7 +559,8 @@ SurfaceImpl::SurfaceImpl() : ownRenderTarget = false; clipsActive = 0; pTextFormat = NULL; - baseline = 1.0f; + yAscent = 2; + yDescent = 1; pBrush = NULL; dpiScaleX = 1.0; dpiScaleY = 1.0; @@ -657,9 +665,10 @@ void SurfaceImpl::D2DPenColour(ColourAllocated fore, int alpha) { } void SurfaceImpl::SetFont(Font &font_) { - FormatAndBaseline *pfabl = reinterpret_cast(font_.GetID()); + FormatAndMetrics *pfabl = reinterpret_cast(font_.GetID()); pTextFormat = pfabl->pTextFormat; - baseline = pfabl->baseline; + yAscent = pfabl->yAscent; + yDescent = pfabl->yDescent; } int SurfaceImpl::LogPixelsY() { @@ -940,14 +949,16 @@ void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, c // 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); + rc.Width(), rc.Height(), &pTextLayout); + // Could be an option for SC_EFF_QUALITY_ANTIALIASED: + //pRenderTarget->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE); if (SUCCEEDED(hr)) { - D2D1_POINT_2F origin = {rc.left, ybase-baseline}; + 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(rcw.left) / dpiScaleX, - static_cast(ybase-baseline) / dpiScaleY, + static_cast(ybase-yAscent) / dpiScaleY, static_cast(rcw.right + 1) / dpiScaleX, static_cast(rcw.bottom) / dpiScaleY); pRenderTarget->DrawText(tbuf.buffer, tbuf.tlen, pTextFormat, layoutRect, pBrush, D2D1_DRAW_TEXT_OPTIONS_NONE); @@ -1108,56 +1119,13 @@ XYPOSITION SurfaceImpl::WidthChar(Font &font_, char ch) { } XYPOSITION SurfaceImpl::Ascent(Font &font_) { - FLOAT ascent = 1.0; SetFont(font_); - 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); + return ceil(yAscent); } XYPOSITION SurfaceImpl::Descent(Font &font_) { - FLOAT descent = 1.0; SetFont(font_); - 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); + return ceil(yDescent); } XYPOSITION SurfaceImpl::InternalLeading(Font &) { @@ -1169,25 +1137,7 @@ XYPOSITION SurfaceImpl::ExternalLeading(Font &) { } XYPOSITION SurfaceImpl::Height(Font &font_) { - FLOAT height = 1.0; - SetFont(font_); - 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); + return Ascent(font_) + Descent(font_); } XYPOSITION SurfaceImpl::AverageCharWidth(Font &font_) { @@ -1660,7 +1610,7 @@ void ListBoxX::SetFont(Font &font) { ::DeleteObject(fontCopy); fontCopy = 0; } - FormatAndBaseline *pfabl = reinterpret_cast(font.GetID()); + FormatAndMetrics *pfabl = reinterpret_cast(font.GetID()); fontCopy = pfabl->HFont(); ::SendMessage(lb, WM_SETFONT, reinterpret_cast(fontCopy), 0); } -- cgit v1.2.3 From 4b3344ecf4e02df4ad1530e4b46d477457d73f95 Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Wed, 10 Aug 2011 11:08:32 +1000 Subject: Implemented text quality parameter. --- win32/PlatWin.cxx | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) (limited to 'win32') diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index 5726e6fb2..8a198eb4b 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -237,14 +237,16 @@ bool LoadD2D() { struct FormatAndMetrics { IDWriteTextFormat *pTextFormat; + int extraFontFlag; FLOAT yAscent; FLOAT yDescent; - FormatAndMetrics(IDWriteTextFormat *pTextFormat_, FLOAT yAscent_, FLOAT yDescent_) : - pTextFormat(pTextFormat_), yAscent(yAscent_), yDescent(yDescent_) { + FormatAndMetrics(IDWriteTextFormat *pTextFormat_, int extraFontFlag_, FLOAT yAscent_, FLOAT yDescent_) : + pTextFormat(pTextFormat_), extraFontFlag(extraFontFlag_), yAscent(yAscent_), yDescent(yDescent_) { } ~FormatAndMetrics() { pTextFormat->Release(); pTextFormat = 0; + extraFontFlag = 0; yAscent = 2; yDescent = 1; } @@ -286,6 +288,23 @@ static BYTE Win32MapFontQuality(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 @@ -366,7 +385,7 @@ FontCached::FontCached(const char *faceName_, int characterSet_, float size_, in } pTextLayout->Release(); } - fid = reinterpret_cast(new FormatAndMetrics(pTextFormat, yAscent, yDescent)); + fid = reinterpret_cast(new FormatAndMetrics(pTextFormat, extraFontFlag_, yAscent, yDescent)); } } usage = 1; @@ -669,6 +688,9 @@ void SurfaceImpl::SetFont(Font &font_) { pTextFormat = pfabl->pTextFormat; yAscent = pfabl->yAscent; yDescent = pfabl->yDescent; + if (pRenderTarget) { + pRenderTarget->SetTextAntialiasMode(DWriteMapFontQuality(pfabl->extraFontFlag)); + } } int SurfaceImpl::LogPixelsY() { @@ -950,8 +972,6 @@ void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, c IDWriteTextLayout *pTextLayout; HRESULT hr = pIDWriteFactory->CreateTextLayout(tbuf.buffer, tbuf.tlen, pTextFormat, rc.Width(), rc.Height(), &pTextLayout); - // Could be an option for SC_EFF_QUALITY_ANTIALIASED: - //pRenderTarget->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE); if (SUCCEEDED(hr)) { D2D1_POINT_2F origin = {rc.left, ybase-yAscent}; pRenderTarget->DrawTextLayout(origin, pTextLayout, pBrush, D2D1_DRAW_TEXT_OPTIONS_NONE); -- cgit v1.2.3 From 6860b289d19541ccb8d5be31c81c0f1aa992e9d7 Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Wed, 10 Aug 2011 23:56:59 +1000 Subject: Implement 'technology' concept which will allow GDI and Direct2D/DirectWrite to run at the same time for different windows and operations. --- win32/PlatWin.cxx | 77 +++++++++++++++++++++++++------------------------- win32/ScintillaWin.cxx | 12 +++++++- 2 files changed, 50 insertions(+), 39 deletions(-) (limited to 'win32') diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index 8a198eb4b..6304d2e5e 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -321,14 +321,14 @@ static void SetLogFont(LOGFONTA &lf, const char *faceName, int characterSet, flo * 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, float size, int weight, bool italic, int extraFontFlag) { +static int HashFont(const FontParameters &fp) { return - static_cast(size) ^ - (characterSet << 10) ^ - ((extraFontFlag & SC_EFF_QUALITY_MASK) << 9) ^ - ((weight/100) << 12) ^ - (italic ? 0x20000000 : 0) ^ - faceName[0]; + static_cast(fp.size) ^ + (fp.characterSet << 10) ^ + ((fp.extraFontFlag & SC_EFF_QUALITY_MASK) << 9) ^ + ((fp.weight/100) << 12) ^ + (fp.italic ? 0x20000000 : 0) ^ + fp.faceName[0]; } class FontCached : Font { @@ -337,33 +337,33 @@ class FontCached : Font { float size; LOGFONTA lf; int hash; - FontCached(const char *faceName_, int characterSet_, float size_, int weight_, bool italic_, int extraFontFlag_); + FontCached(const FontParameters &fp); ~FontCached() {} - bool SameAs(const char *faceName_, int characterSet_, float size_, int weight_, bool italic_, int extraFontFlag_); + bool SameAs(const FontParameters &fp); virtual void Release(); static FontCached *first; public: - static FontID FindOrCreate(const char *faceName_, int characterSet_, float size_, int weight_, 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_, float size_, int weight_, bool italic_, int extraFontFlag_) : +FontCached::FontCached(const FontParameters &fp) : next(0), usage(0), size(1.0), hash(0) { - SetLogFont(lf, faceName_, characterSet_, size_, weight_, italic_, extraFontFlag_); - hash = HashFont(faceName_, characterSet_, size_, weight_, italic_, extraFontFlag_); + SetLogFont(lf, fp.faceName, fp.characterSet, fp.size, fp.weight, fp.italic, fp.extraFontFlag); + hash = HashFont(fp); fid = 0; if (pIDWriteFactory) { IDWriteTextFormat *pTextFormat; const int faceSize = 200; WCHAR wszFace[faceSize]; - UTF16FromUTF8(faceName_, strlen(faceName_)+1, wszFace, faceSize); - FLOAT fHeight = size_; - DWRITE_FONT_STYLE style = italic_ ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; + 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(weight_), + static_cast(fp.weight), style, DWRITE_FONT_STRETCH_NORMAL, fHeight, L"en-us", &pTextFormat); if (SUCCEEDED(hr)) { @@ -385,20 +385,20 @@ FontCached::FontCached(const char *faceName_, int characterSet_, float size_, in } pTextLayout->Release(); } - fid = reinterpret_cast(new FormatAndMetrics(pTextFormat, extraFontFlag_, yAscent, yDescent)); + fid = reinterpret_cast(new FormatAndMetrics(pTextFormat, fp.extraFontFlag, yAscent, yDescent)); } } usage = 1; } -bool FontCached::SameAs(const char *faceName_, int characterSet_, float size_, int weight_, bool italic_, int extraFontFlag_) { +bool FontCached::SameAs(const FontParameters &fp) { return - (size == size_) && - (lf.lfWeight == weight_) && - (lf.lfItalic == static_cast(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(fp.italic ? 1 : 0)) && + (lf.lfCharSet == fp.characterSet) && + (lf.lfQuality == Win32MapFontQuality(fp.extraFontFlag)) && + 0 == strcmp(lf.lfFaceName,fp.faceName); } void FontCached::Release() { @@ -406,19 +406,19 @@ void FontCached::Release() { fid = 0; } -FontID FontCached::FindOrCreate(const char *faceName_, int characterSet_, float size_, int weight_, bool italic_, int extraFontFlag_) { +FontID FontCached::FindOrCreate(const FontParameters &fp) { FontID ret = 0; ::EnterCriticalSection(&crPlatformLock); - int hashFind = HashFont(faceName_, characterSet_, size_, weight_, italic_, extraFontFlag_); + int hashFind = HashFont(fp); for (FontCached *cur=first; cur; cur=cur->next) { if ((cur->hash == hashFind) && - cur->SameAs(faceName_, characterSet_, size_, weight_, italic_, extraFontFlag_)) { + cur->SameAs(fp)) { cur->usage++; ret = cur->fid; } } if (ret == 0) { - FontCached *fc = new FontCached(faceName_, characterSet_, size_, weight_, italic_, extraFontFlag_); + FontCached *fc = new FontCached(fp); if (fc) { fc->next = first; first = fc; @@ -457,11 +457,10 @@ Font::~Font() { #define FONTS_CACHED -void Font::Create(const char *faceName, int characterSet, float size, - int weight, bool italic, int extraFontFlag) { +void Font::Create(const FontParameters &fp) { Release(); - if (faceName) - fid = FontCached::FindOrCreate(faceName, characterSet, size, weight, italic, extraFontFlag); + if (fp.faceName) + fid = FontCached::FindOrCreate(fp); } void Font::Release() { @@ -1203,7 +1202,7 @@ void SurfaceImpl::SetDBCSMode(int codePage_) { win9xACPSame = !IsNT() && ((unsigned int)codePage == ::GetACP()); } -Surface *Surface::Allocate() { +Surface *Surface::Allocate(int /* technology */) { return new SurfaceImpl; } @@ -1514,6 +1513,7 @@ ListBox::~ListBox() { class ListBoxX : public ListBox { int lineHeight; FontID fontCopy; + int technology; RGBAImageSet images; LineToItem lti; HWND lb; @@ -1555,7 +1555,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) { @@ -1567,7 +1567,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; @@ -1602,12 +1602,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(parent->GetID()); HINSTANCE hinstanceParent = GetWindowInstance(hwndParent); // Window created as popup so not clipped within parent client area @@ -1800,7 +1801,7 @@ 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) { if (pD2DFactory) { D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties( diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index 28a630246..b3b9d1bb0 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -1127,6 +1127,16 @@ 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(wParam)) { + technology = wParam; + // Invalidate all cached information including layout. + InvalidateStyleRedraw(); + } + } + break; #ifdef SCI_LEXER case SCI_LOADLEXERLIBRARY: @@ -2751,7 +2761,7 @@ 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) { ID2D1HwndRenderTarget *pCTRenderTarget = 0; RECT rc; -- cgit v1.2.3 From f09627bdb8c597bcc8055b6ce370062a06ad1c37 Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Thu, 11 Aug 2011 10:32:39 +1000 Subject: Implemented parallel stacks for GDI and DirectWrite. GDI works but DirectWrite does not draw well and eventuall crashes. --- win32/PlatWin.cxx | 875 +++++++++++++++++++++++++++++++++++++++++++------ win32/ScintillaWin.cxx | 53 +-- 2 files changed, 808 insertions(+), 120 deletions(-) (limited to 'win32') diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index 6304d2e5e..54b455111 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -236,14 +236,21 @@ bool LoadD2D() { } struct FormatAndMetrics { + HFONT hfont; IDWriteTextFormat *pTextFormat; int extraFontFlag; FLOAT yAscent; FLOAT yDescent; FormatAndMetrics(IDWriteTextFormat *pTextFormat_, int extraFontFlag_, FLOAT yAscent_, FLOAT yDescent_) : - pTextFormat(pTextFormat_), extraFontFlag(extraFontFlag_), yAscent(yAscent_), yDescent(yDescent_) { + hfont(0), pTextFormat(pTextFormat_), extraFontFlag(extraFontFlag_), yAscent(yAscent_), yDescent(yDescent_) { + } + FormatAndMetrics(HFONT hfont_, int extraFontFlag_) : + hfont(hfont_), pTextFormat(0), extraFontFlag(extraFontFlag_), yAscent(2), yDescent(1) { } ~FormatAndMetrics() { + if (hfont) + ::DeleteObject(hfont); + if (pTextFormat) pTextFormat->Release(); pTextFormat = 0; extraFontFlag = 0; @@ -328,6 +335,7 @@ static int HashFont(const FontParameters &fp) { ((fp.extraFontFlag & SC_EFF_QUALITY_MASK) << 9) ^ ((fp.weight/100) << 12) ^ (fp.italic ? 0x20000000 : 0) ^ + (fp.technology << 15) ^ fp.faceName[0]; } @@ -336,6 +344,7 @@ class FontCached : Font { int usage; float size; LOGFONTA lf; + int technology; int hash; FontCached(const FontParameters &fp); ~FontCached() {} @@ -353,9 +362,13 @@ FontCached *FontCached::first = 0; FontCached::FontCached(const FontParameters &fp) : next(0), usage(0), size(1.0), hash(0) { SetLogFont(lf, fp.faceName, fp.characterSet, fp.size, fp.weight, fp.italic, fp.extraFontFlag); + technology = fp.technology; hash = HashFont(fp); fid = 0; - if (pIDWriteFactory) { + if (technology == SCWIN_TECH_GDI) { + HFONT hfont = ::CreateFontIndirectA(&lf); + fid = reinterpret_cast(new FormatAndMetrics(hfont, fp.extraFontFlag)); + } else { IDWriteTextFormat *pTextFormat; const int faceSize = 200; WCHAR wszFace[faceSize]; @@ -398,6 +411,7 @@ bool FontCached::SameAs(const FontParameters &fp) { (lf.lfItalic == static_cast(fp.italic ? 1 : 0)) && (lf.lfCharSet == fp.characterSet) && (lf.lfQuality == Win32MapFontQuality(fp.extraFontFlag)) && + (technology == fp.technology) && 0 == strcmp(lf.lfFaceName,fp.faceName); } @@ -469,11 +483,708 @@ void Font::Release() { fid = 0; } +// Buffer to hold strings and string position arrays without always allocating on heap. +// May sometimes have string too long to allocate on stack. So use a fixed stack-allocated buffer +// when less than safe size otherwise allocate on heap and free automatically. +template +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 { +public: + int tlen; + TextWide(const char *s, int len, bool unicodeMode, int codePage=0) : + VarBuffer(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 TextPositions; + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +class SurfaceGDI : public Surface { + bool unicodeMode; + HDC hdc; + bool hdcOwned; + HPEN pen; + HPEN penOld; + HBRUSH brush; + HBRUSH brushOld; + HFONT font; + HFONT fontOld; + HBITMAP bitmap; + HBITMAP bitmapOld; + HPALETTE paletteOld; + int maxWidthMeasure; + int maxLenText; + + int codePage; + // If 9x OS and current code page is same as ANSI code page. + bool win9xACPSame; + + void BrushColor(ColourAllocated back); + void SetFont(Font &font_); + + // Private so SurfaceGDI objects can not be copied + SurfaceGDI(const SurfaceGDI &); + SurfaceGDI &operator=(const SurfaceGDI &); +public: + SurfaceGDI(); + virtual ~SurfaceGDI(); + + void Init(WindowID wid); + void Init(SurfaceID sid, WindowID wid); + void InitPixMap(int width, int height, Surface *surface_, WindowID wid); + + void Release(); + bool Initialised(); + void PenColour(ColourAllocated fore); + int LogPixelsY(); + int DeviceHeightFont(int points); + void MoveTo(int x_, int y_); + void LineTo(int x_, int y_); + void Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back); + void RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back); + void FillRectangle(PRectangle rc, ColourAllocated back); + void FillRectangle(PRectangle rc, Surface &surfacePattern); + void RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back); + void AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, + ColourAllocated outline, int alphaOutline, int flags); + void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage); + void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back); + void Copy(PRectangle rc, Point from, Surface &surfaceSource); + + void DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT fuOptions); + void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); + void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); + void DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore); + void MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions); + XYPOSITION WidthText(Font &font_, const char *s, int len); + XYPOSITION WidthChar(Font &font_, char ch); + XYPOSITION Ascent(Font &font_); + XYPOSITION Descent(Font &font_); + XYPOSITION InternalLeading(Font &font_); + XYPOSITION ExternalLeading(Font &font_); + XYPOSITION Height(Font &font_); + XYPOSITION AverageCharWidth(Font &font_); + + int SetPalette(Palette *pal, bool inBackGround); + void SetClip(PRectangle rc); + void FlushCachedState(); + + void SetUnicodeMode(bool unicodeMode_); + void SetDBCSMode(int codePage_); +}; + +#ifdef SCI_NAMESPACE +} //namespace Scintilla +#endif + +SurfaceGDI::SurfaceGDI() : + unicodeMode(false), + hdc(0), hdcOwned(false), + pen(0), penOld(0), + brush(0), brushOld(0), + font(0), fontOld(0), + bitmap(0), bitmapOld(0), + paletteOld(0) { + // Windows 9x has only a 16 bit coordinate system so break after 30000 pixels + maxWidthMeasure = IsNT() ? INT_MAX : 30000; + // There appears to be a 16 bit string length limit in GDI on NT and a limit of + // 8192 characters on Windows 95. + maxLenText = IsNT() ? 65535 : 8192; + + codePage = 0; + win9xACPSame = false; +} + +SurfaceGDI::~SurfaceGDI() { + Release(); +} + +void SurfaceGDI::Release() { + if (penOld) { + ::SelectObject(reinterpret_cast(hdc), penOld); + ::DeleteObject(pen); + penOld = 0; + } + pen = 0; + if (brushOld) { + ::SelectObject(reinterpret_cast(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), fontOld); + fontOld = 0; + } + font = 0; + if (bitmapOld) { + ::SelectObject(reinterpret_cast(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), + reinterpret_cast(paletteOld), TRUE); + paletteOld = 0; + } + if (hdcOwned) { + ::DeleteDC(reinterpret_cast(hdc)); + hdc = 0; + hdcOwned = false; + } +} + +bool SurfaceGDI::Initialised() { + return hdc != 0; +} + +void SurfaceGDI::Init(WindowID) { + Release(); + hdc = ::CreateCompatibleDC(NULL); + hdcOwned = true; + ::SetTextAlign(reinterpret_cast(hdc), TA_BASELINE); +} + +void SurfaceGDI::Init(SurfaceID sid, WindowID) { + Release(); + hdc = reinterpret_cast(sid); + ::SetTextAlign(reinterpret_cast(hdc), TA_BASELINE); +} + +void SurfaceGDI::InitPixMap(int width, int height, Surface *surface_, WindowID) { + Release(); + hdc = ::CreateCompatibleDC(static_cast(surface_)->hdc); + hdcOwned = true; + bitmap = ::CreateCompatibleBitmap(static_cast(surface_)->hdc, width, height); + bitmapOld = static_cast(::SelectObject(hdc, bitmap)); + ::SetTextAlign(reinterpret_cast(hdc), TA_BASELINE); +} + +void SurfaceGDI::PenColour(ColourAllocated fore) { + if (pen) { + ::SelectObject(hdc, penOld); + ::DeleteObject(pen); + pen = 0; + penOld = 0; + } + pen = ::CreatePen(0,1,fore.AsLong()); + penOld = static_cast(::SelectObject(reinterpret_cast(hdc), pen)); +} + +void SurfaceGDI::BrushColor(ColourAllocated back) { + if (brush) { + ::SelectObject(hdc, brushOld); + ::DeleteObject(brush); + brush = 0; + brushOld = 0; + } + // Only ever want pure, non-dithered brushes + ColourAllocated colourNearest = ::GetNearestColor(hdc, back.AsLong()); + brush = ::CreateSolidBrush(colourNearest.AsLong()); + brushOld = static_cast(::SelectObject(hdc, brush)); +} + +void SurfaceGDI::SetFont(Font &font_) { + if (font_.GetID() != font) { + FormatAndMetrics *pfm = reinterpret_cast(font_.GetID()); + if (fontOld) { + ::SelectObject(hdc, pfm->hfont); + } else { + fontOld = static_cast(::SelectObject(hdc, pfm->hfont)); + } + font = reinterpret_cast(pfm->hfont); + } +} + +int SurfaceGDI::LogPixelsY() { + return ::GetDeviceCaps(hdc, LOGPIXELSY); +} + +int SurfaceGDI::DeviceHeightFont(int points) { + return ::MulDiv(points, LogPixelsY(), 72); +} + +void SurfaceGDI::MoveTo(int x_, int y_) { + ::MoveToEx(hdc, x_, y_, 0); +} + +void SurfaceGDI::LineTo(int x_, int y_) { + ::LineTo(hdc, x_, y_); +} + +void SurfaceGDI::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) { + PenColour(fore); + BrushColor(back); + ::Polygon(hdc, reinterpret_cast(pts), npts); +} + +void SurfaceGDI::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) { + PenColour(fore); + BrushColor(back); + ::Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom); +} + +void SurfaceGDI::FillRectangle(PRectangle rc, ColourAllocated back) { + // Using ExtTextOut rather than a FillRect ensures that no dithering occurs. + // There is no need to allocate a brush either. + RECT rcw = RectFromPRectangle(rc); + ::SetBkColor(hdc, back.AsLong()); + ::ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE, &rcw, TEXT(""), 0, NULL); +} + +void SurfaceGDI::FillRectangle(PRectangle rc, Surface &surfacePattern) { + HBRUSH br; + if (static_cast(surfacePattern).bitmap) + br = ::CreatePatternBrush(static_cast(surfacePattern).bitmap); + else // Something is wrong so display in red + br = ::CreateSolidBrush(RGB(0xff, 0, 0)); + RECT rcw = RectFromPRectangle(rc); + ::FillRect(hdc, &rcw, br); + ::DeleteObject(br); +} + +void SurfaceGDI::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) { + PenColour(fore); + BrushColor(back); + ::RoundRect(hdc, + rc.left + 1, rc.top, + rc.right - 1, rc.bottom, + 8, 8); +} + +// Plot a point into a DWORD buffer symetrically to all 4 qudrants +static void AllFour(DWORD *pixels, int width, int height, int x, int y, DWORD val) { + pixels[y*width+x] = val; + pixels[y*width+width-1-x] = val; + pixels[(height-1-y)*width+x] = val; + pixels[(height-1-y)*width+width-1-x] = val; +} + +#ifndef AC_SRC_OVER +#define AC_SRC_OVER 0x00 +#endif +#ifndef AC_SRC_ALPHA +#define AC_SRC_ALPHA 0x01 +#endif + +static DWORD dwordFromBGRA(byte b, byte g, byte r, byte a) { + union { + byte pixVal[4]; + DWORD val; + } converter; + converter.pixVal[0] = b; + converter.pixVal[1] = g; + converter.pixVal[2] = r; + converter.pixVal[3] = a; + return converter.val; +} + +void SurfaceGDI::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, + ColourAllocated outline, int alphaOutline, int /* flags*/ ) { + if (AlphaBlendFn && rc.Width() > 0) { + HDC hMemDC = ::CreateCompatibleDC(reinterpret_cast(hdc)); + 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(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(GetBValue(fill.AsLong()) * alphaFill / 255), + static_cast(GetGValue(fill.AsLong()) * alphaFill / 255), + static_cast(GetRValue(fill.AsLong()) * alphaFill / 255), + static_cast(alphaFill)); + DWORD valOutline = dwordFromBGRA( + static_cast(GetBValue(outline.AsLong()) * alphaOutline / 255), + static_cast(GetGValue(outline.AsLong()) * alphaOutline / 255), + static_cast(GetRValue(outline.AsLong()) * alphaOutline / 255), + static_cast(alphaOutline)); + DWORD *pixels = reinterpret_cast(image); + for (int y=0; y(hdc), rc.left, rc.top, width, height, hMemDC, 0, 0, width, height, merge); + + SelectBitmap(hMemDC, hbmOld); + ::DeleteObject(hbmMem); + ::DeleteDC(hMemDC); + } else { + BrushColor(outline); + RECT rcw = RectFromPRectangle(rc); + FrameRect(hdc, &rcw, brush); + } +} + +void SurfaceGDI::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) { + if (AlphaBlendFn && rc.Width() > 0) { + HDC hMemDC = ::CreateCompatibleDC(reinterpret_cast(hdc)); + if (rc.Width() > width) + rc.left += (rc.Width() - width) / 2; + rc.right = rc.left + width; + if (rc.Height() > height) + rc.top += (rc.Height() - height) / 2; + rc.bottom = rc.top + height; + + BITMAPINFO bpih = {sizeof(BITMAPINFOHEADER), width, height, 1, 32, BI_RGB, 0, 0, 0, 0, 0}; + unsigned char *image = 0; + HBITMAP hbmMem = CreateDIBSection(reinterpret_cast(hMemDC), &bpih, + DIB_RGB_COLORS, reinterpret_cast(&image), NULL, 0); + HBITMAP hbmOld = SelectBitmap(hMemDC, hbmMem); + + for (int y=height-1; y>=0; y--) { + for (int x=0; x(hdc), rc.left, rc.top, rc.Width(), rc.Height(), hMemDC, 0, 0, width, height, merge); + + SelectBitmap(hMemDC, hbmOld); + ::DeleteObject(hbmMem); + ::DeleteDC(hMemDC); + + } +} + +void SurfaceGDI::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) { + PenColour(fore); + BrushColor(back); + ::Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom); +} + +void SurfaceGDI::Copy(PRectangle rc, Point from, Surface &surfaceSource) { + ::BitBlt(hdc, + rc.left, rc.top, rc.Width(), rc.Height(), + static_cast(surfaceSource).hdc, from.x, from.y, SRCCOPY); +} + +typedef VarBuffer TextPositionsI; + +void SurfaceGDI::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT fuOptions) { + SetFont(font_); + RECT rcw = RectFromPRectangle(rc); + SIZE sz={0,0}; + int pos = 0; + int x = rc.left; + + // Text drawing may fail if the text is too big. + // If it does fail, slice up into segments and draw each segment. + const int maxSegmentLength = 0x200; + + if ((!unicodeMode) && (IsNT() || (codePage==0) || win9xACPSame)) { + // Use ANSI calls + int lenDraw = Platform::Minimum(len, maxLenText); + if (!::ExtTextOutA(hdc, x, ybase, fuOptions, &rcw, s, lenDraw, NULL)) { + while (lenDraw > pos) { + int seglen = Platform::Minimum(maxSegmentLength, lenDraw - pos); + if (!::ExtTextOutA(hdc, x, ybase, fuOptions, &rcw, s+pos, seglen, NULL)) { + PLATFORM_ASSERT(false); + return; + } + ::GetTextExtentPoint32A(hdc, s+pos, seglen, &sz); + x += sz.cx; + pos += seglen; + } + } + } else { + // Use Unicode calls + const TextWide tbuf(s, len, unicodeMode, codePage); + if (!::ExtTextOutW(hdc, x, ybase, fuOptions, &rcw, tbuf.buffer, tbuf.tlen, NULL)) { + while (tbuf.tlen > pos) { + int seglen = Platform::Minimum(maxSegmentLength, tbuf.tlen - pos); + if (!::ExtTextOutW(hdc, x, ybase, fuOptions, &rcw, tbuf.buffer+pos, seglen, NULL)) { + PLATFORM_ASSERT(false); + return; + } + ::GetTextExtentPoint32W(hdc, tbuf.buffer+pos, seglen, &sz); + x += sz.cx; + pos += seglen; + } + } + } +} + +void SurfaceGDI::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, + ColourAllocated fore, ColourAllocated back) { + ::SetTextColor(hdc, fore.AsLong()); + ::SetBkColor(hdc, back.AsLong()); + DrawTextCommon(rc, font_, ybase, s, len, ETO_OPAQUE); +} + +void SurfaceGDI::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, + ColourAllocated fore, ColourAllocated back) { + ::SetTextColor(hdc, fore.AsLong()); + ::SetBkColor(hdc, back.AsLong()); + DrawTextCommon(rc, font_, ybase, s, len, ETO_OPAQUE | ETO_CLIPPED); +} + +void SurfaceGDI::DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, + ColourAllocated fore) { + // Avoid drawing spaces in transparent mode + for (int i=0;i(s); + int i=0; + while (ui= (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 0) + lastPos = positions[i-1]; + while (i 0) { + int lenBlock = Platform::Minimum(len, maxLenText); + TextPositionsI poses(len); + if (!::GetTextExtentExPointA(hdc, s, lenBlock, maxWidthMeasure, &fit, poses.buffer, &sz)) { + // Eeek - a NULL DC or other foolishness could cause this. + return; + } else if (fit < lenBlock) { + // For some reason, such as an incomplete DBCS character + // Not all the positions are filled in so make them equal to end. + for (int i = fit;iallowRealization) { + paletteOld = ::SelectPalette(hdc, + reinterpret_cast(pal->hpal), inBackGround); + changes = ::RealizePalette(hdc); + } + return changes; +} + +void SurfaceGDI::SetClip(PRectangle rc) { + ::IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom); +} + +void SurfaceGDI::FlushCachedState() { + pen = 0; + brush = 0; + font = 0; +} + +void SurfaceGDI::SetUnicodeMode(bool unicodeMode_) { + unicodeMode=unicodeMode_; +} + +void SurfaceGDI::SetDBCSMode(int codePage_) { + // No action on window as automatically handled by system. + codePage = codePage_; + win9xACPSame = !IsNT() && ((unsigned int)codePage == ::GetACP()); +} + #ifdef SCI_NAMESPACE namespace Scintilla { #endif -class SurfaceImpl : public Surface { +class SurfaceD2D : public Surface { bool unicodeMode; HDC hdc; bool hdcOwned; @@ -500,12 +1211,12 @@ class SurfaceImpl : public Surface { void SetFont(Font &font_); - // Private so SurfaceImpl objects can not be copied - SurfaceImpl(const SurfaceImpl &); - SurfaceImpl &operator=(const SurfaceImpl &); + // Private so SurfaceD2D objects can not be copied + SurfaceD2D(const SurfaceD2D &); + SurfaceD2D &operator=(const SurfaceD2D &); public: - SurfaceImpl(); - virtual ~SurfaceImpl(); + SurfaceD2D(); + virtual ~SurfaceD2D(); void SetDWrite(HDC hdc); void Init(WindowID wid); @@ -560,7 +1271,7 @@ public: } //namespace Scintilla #endif -SurfaceImpl::SurfaceImpl() : +SurfaceD2D::SurfaceD2D() : unicodeMode(false), hdc(0), hdcOwned(false), x(0), y(0) { @@ -585,11 +1296,11 @@ SurfaceImpl::SurfaceImpl() : hasBegun = false; } -SurfaceImpl::~SurfaceImpl() { +SurfaceD2D::~SurfaceD2D() { Release(); } -void SurfaceImpl::Release() { +void SurfaceD2D::Release() { if (hdcOwned) { ::DeleteDC(reinterpret_cast(hdc)); hdc = 0; @@ -612,20 +1323,20 @@ void SurfaceImpl::Release() { } } -void SurfaceImpl::SetDWrite(HDC hdc) { +void SurfaceD2D::SetDWrite(HDC hdc) { dpiScaleX = GetDeviceCaps(hdc, LOGPIXELSX) / 96.0f; dpiScaleY = GetDeviceCaps(hdc, LOGPIXELSY) / 96.0f; } -bool SurfaceImpl::Initialised() { +bool SurfaceD2D::Initialised() { return pRenderTarget != 0; } -HRESULT SurfaceImpl::FlushDrawing() { +HRESULT SurfaceD2D::FlushDrawing() { return pRenderTarget->Flush(); } -void SurfaceImpl::Init(WindowID wid) { +void SurfaceD2D::Init(WindowID wid) { Release(); hdc = ::CreateCompatibleDC(NULL); hdcOwned = true; @@ -635,7 +1346,7 @@ void SurfaceImpl::Init(WindowID wid) { SetDWrite(hdc); } -void SurfaceImpl::Init(SurfaceID sid, WindowID) { +void SurfaceD2D::Init(SurfaceID sid, WindowID) { Release(); hdc = ::CreateCompatibleDC(NULL); hdcOwned = true; @@ -644,11 +1355,11 @@ void SurfaceImpl::Init(SurfaceID sid, WindowID) { SetDWrite(hdc); } -void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID) { +void SurfaceD2D::InitPixMap(int width, int height, Surface *surface_, WindowID) { Release(); hdc = ::CreateCompatibleDC(NULL); // Just for measurement hdcOwned = true; - SurfaceImpl *psurfOther = static_cast(surface_); + SurfaceD2D *psurfOther = static_cast(surface_); ID2D1BitmapRenderTarget *pCompatibleRenderTarget = NULL; HRESULT hr = psurfOther->pRenderTarget->CreateCompatibleRenderTarget( D2D1::SizeF(width, height), &pCompatibleRenderTarget); @@ -659,11 +1370,11 @@ void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID) } } -void SurfaceImpl::PenColour(ColourAllocated fore) { +void SurfaceD2D::PenColour(ColourAllocated fore) { D2DPenColour(fore); } -void SurfaceImpl::D2DPenColour(ColourAllocated fore, int alpha) { +void SurfaceD2D::D2DPenColour(ColourAllocated fore, int alpha) { if (pRenderTarget) { D2D_COLOR_F col; col.r = (fore.AsLong() & 0xff) / 255.0; @@ -682,25 +1393,25 @@ void SurfaceImpl::D2DPenColour(ColourAllocated fore, int alpha) { } } -void SurfaceImpl::SetFont(Font &font_) { - FormatAndMetrics *pfabl = reinterpret_cast(font_.GetID()); - pTextFormat = pfabl->pTextFormat; - yAscent = pfabl->yAscent; - yDescent = pfabl->yDescent; +void SurfaceD2D::SetFont(Font &font_) { + FormatAndMetrics *pfm = reinterpret_cast(font_.GetID()); + pTextFormat = pfm->pTextFormat; + yAscent = pfm->yAscent; + yDescent = pfm->yDescent; if (pRenderTarget) { - pRenderTarget->SetTextAntialiasMode(DWriteMapFontQuality(pfabl->extraFontFlag)); + pRenderTarget->SetTextAntialiasMode(DWriteMapFontQuality(pfm->extraFontFlag)); } } -int SurfaceImpl::LogPixelsY() { +int SurfaceD2D::LogPixelsY() { return ::GetDeviceCaps(hdc, LOGPIXELSY); } -int SurfaceImpl::DeviceHeightFont(int points) { +int SurfaceD2D::DeviceHeightFont(int points) { return ::MulDiv(points, LogPixelsY(), 72); } -void SurfaceImpl::MoveTo(int x_, int y_) { +void SurfaceD2D::MoveTo(int x_, int y_) { x = x_; y = y_; } @@ -718,7 +1429,7 @@ static int RoundFloat(float f) { return int(f+0.5); } -void SurfaceImpl::LineTo(int x_, int y_) { +void SurfaceD2D::LineTo(int x_, int y_) { if (pRenderTarget) { int xDiff = x_ - x; int xDelta = Delta(xDiff); @@ -748,7 +1459,7 @@ void SurfaceImpl::LineTo(int x_, int y_) { } } -void SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) { +void SurfaceD2D::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) { if (pRenderTarget) { ID2D1Factory *pFactory = 0; pRenderTarget->GetFactory(&pFactory); @@ -777,7 +1488,7 @@ void SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllo } } -void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) { +void SurfaceD2D::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) { if (pRenderTarget) { D2DPenColour(back); D2D1_RECT_F rectangle1 = D2D1::RectF(RoundFloat(rc.left) + 0.5, rc.top+0.5, RoundFloat(rc.right) - 0.5, rc.bottom-0.5); @@ -788,7 +1499,7 @@ void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAlloc } } -void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) { +void SurfaceD2D::FillRectangle(PRectangle rc, ColourAllocated back) { if (pRenderTarget) { D2DPenColour(back); D2D1_RECT_F rectangle1 = D2D1::RectF(RoundFloat(rc.left), rc.top, RoundFloat(rc.right), rc.bottom); @@ -796,8 +1507,8 @@ void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) { } } -void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) { - SurfaceImpl &surfOther = static_cast(surfacePattern); +void SurfaceD2D::FillRectangle(PRectangle rc, Surface &surfacePattern) { + SurfaceD2D &surfOther = static_cast(surfacePattern); surfOther.FlushDrawing(); ID2D1Bitmap *pBitmap = NULL; ID2D1BitmapRenderTarget *pCompatibleRenderTarget = reinterpret_cast( @@ -820,7 +1531,7 @@ void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) { } } -void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) { +void SurfaceD2D::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) { if (pRenderTarget) { D2D1_ROUNDED_RECT roundedRectFill = D2D1::RoundedRect( D2D1::RectF(rc.left+1.0, rc.top+1.0, rc.right-1.0, rc.bottom-1.0), @@ -836,7 +1547,7 @@ void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAl } } -void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, +void SurfaceD2D::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, ColourAllocated outline, int alphaOutline, int /* flags*/ ) { if (pRenderTarget) { D2D1_ROUNDED_RECT roundedRectFill = D2D1::RoundedRect( @@ -853,7 +1564,7 @@ void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated } } -void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) { +void SurfaceD2D::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) { if (pRenderTarget) { if (rc.Width() > width) rc.left += (rc.Width() - width) / 2; @@ -889,7 +1600,7 @@ void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsi } } -void SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) { +void SurfaceD2D::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) { if (pRenderTarget) { FLOAT radius = rc.Width() / 2.0f - 1.0f; D2D1_ELLIPSE ellipse = D2D1::Ellipse( @@ -903,8 +1614,8 @@ void SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated b } } -void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) { - SurfaceImpl &surfOther = static_cast(surfaceSource); +void SurfaceD2D::Copy(PRectangle rc, Point from, Surface &surfaceSource) { + SurfaceD2D &surfOther = static_cast(surfaceSource); surfOther.FlushDrawing(); ID2D1BitmapRenderTarget *pCompatibleRenderTarget = reinterpret_cast( surfOther.pRenderTarget); @@ -920,46 +1631,7 @@ void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) { } } -// Buffer to hold strings and string position arrays without always allocating on heap. -// May sometimes have string too long to allocate on stack. So use a fixed stack-allocated buffer -// when less than safe size otherwise allocate on heap and free automatically. -template -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 { -public: - int tlen; - TextWide(const char *s, int len, bool unicodeMode, int codePage=0) : - VarBuffer(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 TextPositions; - -void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT) { +void SurfaceD2D::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT) { SetFont(font_); RECT rcw = RectFromPRectangle(rc); @@ -985,7 +1657,7 @@ void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, c } } -void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, +void SurfaceD2D::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back) { if (pRenderTarget) { FillRectangle(rc, back); @@ -994,7 +1666,7 @@ void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, c } } -void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, +void SurfaceD2D::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back) { if (pRenderTarget) { FillRectangle(rc, back); @@ -1003,7 +1675,7 @@ void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, } } -void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, +void SurfaceD2D::DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore) { // Avoid drawing spaces in transparent mode for (int i=0;iPushAxisAlignedClip(rcClip, D2D1_ANTIALIAS_MODE_ALIASED); @@ -1189,21 +1861,24 @@ void SurfaceImpl::SetClip(PRectangle rc) { } } -void SurfaceImpl::FlushCachedState() { +void SurfaceD2D::FlushCachedState() { } -void SurfaceImpl::SetUnicodeMode(bool unicodeMode_) { +void SurfaceD2D::SetUnicodeMode(bool unicodeMode_) { unicodeMode=unicodeMode_; } -void SurfaceImpl::SetDBCSMode(int codePage_) { +void SurfaceD2D::SetDBCSMode(int codePage_) { // No action on window as automatically handled by system. codePage = codePage_; win9xACPSame = !IsNT() && ((unsigned int)codePage == ::GetACP()); } -Surface *Surface::Allocate(int /* technology */) { - return new SurfaceImpl; +Surface *Surface::Allocate(int technology) { + if (technology == SCWIN_TECH_GDI) + return new SurfaceGDI; + else + return new SurfaceD2D; } Window::~Window() { diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index b3b9d1bb0..525621b2c 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -383,8 +383,6 @@ void ScintillaWin::Initialise() { ::GetProcAddress(commctrl32, "_TrackMouseEvent"); } } - - LoadD2D(); } void ScintillaWin::Finalise() { @@ -546,25 +544,35 @@ LRESULT ScintillaWin::WndPaint(uptr_t wParam) { pps = &ps; ::BeginPaint(MainHWND(), pps); } - //AutoSurface surfaceWindow(pps->hdc, this); - EnsureRenderTarget(); - AutoSurface surfaceWindow(pRenderTarget, this); - if (surfaceWindow) { - pRenderTarget->BeginDraw(); - rcPaint = PRectangle(pps->rcPaint.left, pps->rcPaint.top, pps->rcPaint.right, pps->rcPaint.bottom); - PRectangle rcClient = GetClientRectangle(); - paintingAllText = rcPaint.Contains(rcClient); - if (paintingAllText) { - //Platform::DebugPrintf("Performing full text paint\n"); - } else { - //Platform::DebugPrintf("Performing partial paint %d .. %d\n", rcPaint.top, rcPaint.bottom); + if (technology == SC_TECHNOLOGY_DEFAULT) { + AutoSurface surfaceWindow(pps->hdc, this); + if (surfaceWindow) { + rcPaint = PRectangle(pps->rcPaint.left, pps->rcPaint.top, pps->rcPaint.right, pps->rcPaint.bottom); + PRectangle rcClient = GetClientRectangle(); + paintingAllText = rcPaint.Contains(rcClient); + Paint(surfaceWindow, rcPaint); + surfaceWindow->Release(); + } + } else { + EnsureRenderTarget(); + AutoSurface surfaceWindow(pRenderTarget, this); + if (surfaceWindow) { + pRenderTarget->BeginDraw(); + rcPaint = PRectangle(pps->rcPaint.left, pps->rcPaint.top, pps->rcPaint.right, pps->rcPaint.bottom); + PRectangle rcClient = GetClientRectangle(); + paintingAllText = rcPaint.Contains(rcClient); + if (paintingAllText) { + //Platform::DebugPrintf("Performing full text paint\n"); + } else { + //Platform::DebugPrintf("Performing partial paint %d .. %d\n", rcPaint.top, rcPaint.bottom); + } + Paint(surfaceWindow, rcPaint); + surfaceWindow->Release(); + HRESULT hr = pRenderTarget->EndDraw(); + if (hr == D2DERR_RECREATE_TARGET) { + DropRenderTarget(); + } } - Paint(surfaceWindow, rcPaint); - surfaceWindow->Release(); - HRESULT hr = pRenderTarget->EndDraw(); - if (hr == D2DERR_RECREATE_TARGET) { - DropRenderTarget(); - } } if (hRgnUpdate) { ::DeleteRgn(hRgnUpdate); @@ -1131,6 +1139,11 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam case SCI_SETTECHNOLOGY: if ((wParam == SC_TECHNOLOGY_DEFAULT) || (wParam == SC_TECHNOLOGY_DIRECTWRITE)) { if (technology != static_cast(wParam)) { + if (static_cast(wParam) == SC_TECHNOLOGY_DIRECTWRITE) { + if (!LoadD2D()) + // Failed to load Direct2D or DirectWrite so no effect + return 0; + } technology = wParam; // Invalidate all cached information including layout. InvalidateStyleRedraw(); -- cgit v1.2.3 From 0f82453d4bcbdff2d0298bf23c8e5154d4674fc9 Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Thu, 11 Aug 2011 12:09:27 +1000 Subject: Parallel stacks for GDI and DirectWrite works. --- win32/PlatWin.cxx | 37 ++++++++++++++++++++++--------------- win32/ScintillaWin.cxx | 42 +++++++++++++++++++++++++++--------------- 2 files changed, 49 insertions(+), 30 deletions(-) (limited to 'win32') diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index 54b455111..2849144e1 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -236,16 +236,17 @@ bool LoadD2D() { } struct FormatAndMetrics { + int technology; HFONT hfont; IDWriteTextFormat *pTextFormat; int extraFontFlag; FLOAT yAscent; FLOAT yDescent; - FormatAndMetrics(IDWriteTextFormat *pTextFormat_, int extraFontFlag_, FLOAT yAscent_, FLOAT yDescent_) : - hfont(0), pTextFormat(pTextFormat_), extraFontFlag(extraFontFlag_), yAscent(yAscent_), yDescent(yDescent_) { - } FormatAndMetrics(HFONT hfont_, int extraFontFlag_) : - hfont(hfont_), pTextFormat(0), extraFontFlag(extraFontFlag_), yAscent(2), yDescent(1) { + 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) @@ -261,15 +262,19 @@ struct FormatAndMetrics { }; HFONT FormatAndMetrics::HFont() { - LOGFONTW lf; - memset(&lf, 0, sizeof(lf)); + 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(pTextFormat->GetFontSize()); - return ::CreateFontIndirectW(&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(pTextFormat->GetFontSize()); + return ::CreateFontIndirectW(&lf); + } } return 0; } @@ -315,7 +320,7 @@ static D2D1_TEXT_ANTIALIAS_MODE DWriteMapFontQuality(int extraFontFlag) { 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(static_cast(size))); + lf.lfHeight = -(abs(static_cast(size + 0.5))); lf.lfWeight = weight; lf.lfItalic = static_cast(italic ? 1 : 0); lf.lfCharSet = static_cast(characterSet); @@ -717,6 +722,7 @@ void SurfaceGDI::BrushColor(ColourAllocated back) { void SurfaceGDI::SetFont(Font &font_) { if (font_.GetID() != font) { FormatAndMetrics *pfm = reinterpret_cast(font_.GetID()); + PLATFORM_ASSERT(pfm->technology == SCWIN_TECH_GDI); if (fontOld) { ::SelectObject(hdc, pfm->hfont); } else { @@ -1395,6 +1401,7 @@ void SurfaceD2D::D2DPenColour(ColourAllocated fore, int alpha) { void SurfaceD2D::SetFont(Font &font_) { FormatAndMetrics *pfm = reinterpret_cast(font_.GetID()); + PLATFORM_ASSERT(pfm->technology == SCWIN_TECH_DIRECTWRITE); pTextFormat = pfm->pTextFormat; yAscent = pfm->yAscent; yDescent = pfm->yDescent; @@ -2306,8 +2313,8 @@ void ListBoxX::SetFont(Font &font) { ::DeleteObject(fontCopy); fontCopy = 0; } - FormatAndMetrics *pfabl = reinterpret_cast(font.GetID()); - fontCopy = pfabl->HFont(); + FormatAndMetrics *pfm = reinterpret_cast(font.GetID()); + fontCopy = pfm->HFont(); ::SendMessage(lb, WM_SETFONT, reinterpret_cast(fontCopy), 0); } } diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index 525621b2c..bfc4c1b43 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -1146,6 +1146,7 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam } technology = wParam; // Invalidate all cached information including layout. + DropGraphics(true); InvalidateStyleRedraw(); } } @@ -2379,30 +2380,41 @@ void ScintillaWin::RealizeWindowPalette(bool) { * This paint will not be abandoned. */ void ScintillaWin::FullPaint() { - //HDC hdc = ::GetDC(MainHWND()); - //FullPaintDC(hdc); - //::ReleaseDC(MainHWND(), hdc); - FullPaintDC(0); + if (technology == SC_TECHNOLOGY_DEFAULT) { + HDC hdc = ::GetDC(MainHWND()); + FullPaintDC(hdc); + ::ReleaseDC(MainHWND(), hdc); + } else { + FullPaintDC(0); + } } /** * Redraw all of text area on the specified DC. * This paint will not be abandoned. */ -void ScintillaWin::FullPaintDC(HDC) { +void ScintillaWin::FullPaintDC(HDC hdc) { paintState = painting; rcPaint = GetClientRectangle(); paintingAllText = true; - EnsureRenderTarget(); - AutoSurface surfaceWindow(pRenderTarget, this); - if (surfaceWindow) { - pRenderTarget->BeginDraw(); - Paint(surfaceWindow, rcPaint); - surfaceWindow->Release(); - HRESULT hr = pRenderTarget->EndDraw(); - if (hr == D2DERR_RECREATE_TARGET) { - DropRenderTarget(); - } + 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; } -- cgit v1.2.3 From 418b4a0ab5ba38e060a9c843845a944b23ef86c6 Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Thu, 11 Aug 2011 13:17:37 +1000 Subject: Fix bugs in calltip and autocompletion with technology choice. Simplified Direct2D code. --- win32/PlatWin.cxx | 71 +++++++++++++++++++++----------------------------- win32/ScintillaWin.cxx | 23 +++++++++------- 2 files changed, 43 insertions(+), 51 deletions(-) (limited to 'win32') diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index 2849144e1..f3c063c1b 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -1192,15 +1192,9 @@ namespace Scintilla { class SurfaceD2D : public Surface { bool unicodeMode; - HDC hdc; - bool hdcOwned; - int maxWidthMeasure; - int maxLenText; int x, y; int codePage; - // If 9x OS and current code page is same as ANSI code page. - bool win9xACPSame; ID2D1RenderTarget *pRenderTarget; bool ownRenderTarget; @@ -1211,9 +1205,10 @@ class SurfaceD2D : public Surface { FLOAT yDescent; ID2D1SolidColorBrush *pBrush; + + int logPixelsY; float dpiScaleX; float dpiScaleY; - bool hasBegun; void SetFont(Font &font_); @@ -1224,7 +1219,7 @@ public: SurfaceD2D(); virtual ~SurfaceD2D(); - void SetDWrite(HDC hdc); + void SetScale(); void Init(WindowID wid); void Init(SurfaceID sid, WindowID wid); void InitPixMap(int width, int height, Surface *surface_, WindowID wid); @@ -1279,27 +1274,24 @@ public: SurfaceD2D::SurfaceD2D() : unicodeMode(false), - 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 - // 8192 characters on Windows 95. - maxLenText = IsNT() ? 65535 : 8192; codePage = 0; - win9xACPSame = false; 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; - hasBegun = false; } SurfaceD2D::~SurfaceD2D() { @@ -1307,12 +1299,6 @@ SurfaceD2D::~SurfaceD2D() { } void SurfaceD2D::Release() { - if (hdcOwned) { - ::DeleteDC(reinterpret_cast(hdc)); - hdc = 0; - hdcOwned = false; - } - if (pBrush) { pBrush->Release(); pBrush = 0; @@ -1329,9 +1315,12 @@ void SurfaceD2D::Release() { } } -void SurfaceD2D::SetDWrite(HDC hdc) { - dpiScaleX = GetDeviceCaps(hdc, LOGPIXELSX) / 96.0f; - dpiScaleY = GetDeviceCaps(hdc, LOGPIXELSY) / 96.0f; +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() { @@ -1342,29 +1331,20 @@ HRESULT SurfaceD2D::FlushDrawing() { return pRenderTarget->Flush(); } -void SurfaceD2D::Init(WindowID wid) { +void SurfaceD2D::Init(WindowID /* wid */) { Release(); - hdc = ::CreateCompatibleDC(NULL); - hdcOwned = true; - ::SetTextAlign(reinterpret_cast(hdc), TA_BASELINE); - RECT rc; - ::GetClientRect(reinterpret_cast(wid), &rc); - SetDWrite(hdc); + SetScale(); } void SurfaceD2D::Init(SurfaceID sid, WindowID) { Release(); - hdc = ::CreateCompatibleDC(NULL); - hdcOwned = true; + SetScale(); pRenderTarget = reinterpret_cast(sid); - ::SetTextAlign(reinterpret_cast(hdc), TA_BASELINE); - SetDWrite(hdc); } void SurfaceD2D::InitPixMap(int width, int height, Surface *surface_, WindowID) { Release(); - hdc = ::CreateCompatibleDC(NULL); // Just for measurement - hdcOwned = true; + SetScale(); SurfaceD2D *psurfOther = static_cast(surface_); ID2D1BitmapRenderTarget *pCompatibleRenderTarget = NULL; HRESULT hr = psurfOther->pRenderTarget->CreateCompatibleRenderTarget( @@ -1411,7 +1391,7 @@ void SurfaceD2D::SetFont(Font &font_) { } int SurfaceD2D::LogPixelsY() { - return ::GetDeviceCaps(hdc, LOGPIXELSY); + return logPixelsY; } int SurfaceD2D::DeviceHeightFont(int points) { @@ -1878,7 +1858,6 @@ void SurfaceD2D::SetUnicodeMode(bool unicodeMode_) { void SurfaceD2D::SetDBCSMode(int codePage_) { // No action on window as automatically handled by system. codePage = codePage_; - win9xACPSame = !IsNT() && ((unsigned int)codePage == ::GetACP()); } Surface *Surface::Allocate(int technology) { @@ -2485,7 +2464,16 @@ void ListBoxX::Draw(DRAWITEMSTRUCT *pDrawItem) { if (pimage) { Surface *surfaceItem = Surface::Allocate(technology); if (surfaceItem) { - if (pD2DFactory) { + 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( @@ -2510,7 +2498,6 @@ void ListBoxX::Draw(DRAWITEMSTRUCT *pDrawItem) { surfaceItem->DrawRGBAImage(rcImage, pimage->GetWidth(), pimage->GetHeight(), pimage->Pixels()); delete surfaceItem; - ::SetTextAlign(pDrawItem->hDC, TA_TOP); pDCRT->EndDraw(); pDCRT->Release(); } diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index bfc4c1b43..c16da8fdb 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -2792,20 +2792,25 @@ sptr_t PASCAL ScintillaWin::CTWndProc( RECT rc; GetClientRect(hWnd, &rc); // Create a Direct2D render target. - 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); + 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); - pCTRenderTarget->BeginDraw(); sciThis->ct.PaintCT(surfaceWindow); - pCTRenderTarget->EndDraw(); + if (pCTRenderTarget) + pCTRenderTarget->EndDraw(); surfaceWindow->Release(); delete surfaceWindow; - pCTRenderTarget->Release(); + if (pCTRenderTarget) + pCTRenderTarget->Release(); } ::EndPaint(hWnd, &ps); return 0; -- cgit v1.2.3