From b936bfe85efaf0e179ec6ce071853934aecdf43a Mon Sep 17 00:00:00 2001 From: New Pagodi Date: Thu, 25 Jan 2018 16:07:54 -0600 Subject: [PATCH] Add Direct2D support to wxSTC --- include/wx/msw/private/graphicsd2d.h | 28 + include/wx/stc/stc.h | 6 + interface/wx/stc/stc.h | 27 +- src/msw/graphicsd2d.cpp | 51 +- src/stc/PlatWX.cpp | 1196 +++++++++++++++++++++++++- src/stc/PlatWX.h | 66 ++ src/stc/ScintillaWX.cpp | 40 +- src/stc/ScintillaWX.h | 4 + src/stc/gen_docs.py | 26 +- src/stc/gen_iface.py | 2 - src/stc/stc.cpp | 16 + src/stc/stc.cpp.in | 4 + 12 files changed, 1449 insertions(+), 17 deletions(-) create mode 100644 include/wx/msw/private/graphicsd2d.h diff --git a/include/wx/msw/private/graphicsd2d.h b/include/wx/msw/private/graphicsd2d.h new file mode 100644 index 0000000000..993f61a960 --- /dev/null +++ b/include/wx/msw/private/graphicsd2d.h @@ -0,0 +1,28 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/msw/private/graphicsd2d.h +// Purpose: Allow functions from graphicsd2d.cpp to be used in othe files +// Author: New Pagodi +// Created: 2017-10-31 +// Copyright: (c) 2017 wxWidgets development team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef WX_MSW_PRIVATE_GRAPHICSD2D_H_ +#define WX_MSW_PRIVATE_GRAPHICSD2D_H_ + +#if wxUSE_GRAPHICS_DIRECT2D + +// Ensure no previous defines interfere with the Direct2D API headers +#undef GetHwnd + +#include +#include +#include + +WXDLLIMPEXP_CORE IWICImagingFactory* wxWICImagingFactory(); +WXDLLIMPEXP_CORE ID2D1Factory* wxD2D1Factory(); +WXDLLIMPEXP_CORE IDWriteFactory* wxDWriteFactory(); + +#endif // wxUSE_GRAPHICS_DIRECT2D + +#endif // WX_MSW_PRIVATE_GRAPHICSD2D_H_ diff --git a/include/wx/stc/stc.h b/include/wx/stc/stc.h index 36c7c1d900..43b4e97b6f 100644 --- a/include/wx/stc/stc.h +++ b/include/wx/stc/stc.h @@ -3963,6 +3963,12 @@ public: // to overlap from one line to the next. void SetPhasesDraw(int phases); + // Choose the quality level for text. + void SetFontQuality(int fontQuality); + + // Retrieve the quality level for text. + int GetFontQuality() const; + // Scroll so that a display line is at the top of the display. void SetFirstVisibleLine(int displayLine); diff --git a/interface/wx/stc/stc.h b/interface/wx/stc/stc.h index e65f64c40e..49ef8ff5ad 100644 --- a/interface/wx/stc/stc.h +++ b/interface/wx/stc/stc.h @@ -5153,6 +5153,27 @@ public: */ void SetPhasesDraw(int phases); + /** + Choose the quality level for text. + + The input should be one of the + @link wxStyledTextCtrl::wxSTC_EFF_QUALITY_DEFAULT wxSTC_EFF_QUALITY_* @endlink constants. + @remarks + This method only has any effect with the wxMSW port and when + technology has been set to wxSTC_TECHNOLOGY_DIRECTWRITE. + @since 3.1.1 + */ + void SetFontQuality(int fontQuality); + + /** + Retrieve the quality level for text. + + The return value will be one of the + @link wxStyledTextCtrl::wxSTC_EFF_QUALITY_DEFAULT wxSTC_EFF_QUALITY_* @endlink constants. + @since 3.1.1 + */ + int GetFontQuality() const; + /** Change internal focus flag. */ @@ -5166,8 +5187,10 @@ public: /** Set the technology used. - The input should be one of the - @link wxStyledTextCtrl::wxSTC_TECHNOLOGY_DEFAULT wxSTC_TECHNOLOGY_* @endlink constants. + @remarks + For the wxMSW port, the input can be either wxSTC_TECHNOLOGY_DEFAULT + or wxSTC_TECHNOLOGY_DIRECTWRITE. With other ports, this method has + no effect. */ void SetTechnology(int technology); diff --git a/src/msw/graphicsd2d.cpp b/src/msw/graphicsd2d.cpp index 22306f9169..ad502cc43e 100644 --- a/src/msw/graphicsd2d.cpp +++ b/src/msw/graphicsd2d.cpp @@ -72,6 +72,7 @@ #include "wx/private/graphics.h" #include "wx/stack.h" #include "wx/sharedptr.h" +#include "wx/msw/private/graphicsd2d.h" // This must be the last header included to only affect the DEFINE_GUID() // occurrences below but not any GUIDs declared in the standard files included @@ -219,6 +220,9 @@ wxDirect2D::DWriteCreateFactory_t wxDirect2D::DWriteCreateFactory = NULL; DEFINE_GUID(wxIID_IWICImagingFactory, 0xec5ec8a9, 0xc395, 0x4314, 0x9c, 0x77, 0x54, 0xd7, 0xa9, 0x35, 0xff, 0x70); +DEFINE_GUID(wxIID_ID2D1Factory, + 0x06152247, 0x6f50, 0x465a, 0x92, 0x45, 0x11, 0x8b, 0xfd, 0x3b, 0x60, 0x07); + DEFINE_GUID(wxIID_IDWriteFactory, 0xb859ee5a, 0xd838, 0x4b5b, 0xa2, 0xe8, 0x1a, 0xdc, 0x7d, 0x93, 0xdb, 0x48); @@ -299,6 +303,39 @@ IWICImagingFactory* wxWICImagingFactory() return gs_WICImagingFactory; } +static ID2D1Factory* gs_ID2D1Factory = NULL; + +ID2D1Factory* wxD2D1Factory() +{ + if (!wxDirect2D::Initialize()) + return NULL; + + if (gs_ID2D1Factory == NULL) + { + D2D1_FACTORY_OPTIONS factoryOptions = {D2D1_DEBUG_LEVEL_NONE}; + + // According to + // https://msdn.microsoft.com/en-us/library/windows/desktop/ee794287(v=vs.85).aspx + // the Direct2D Debug Layer is only available starting with Windows 8 + // and Visual Studio 2012. +#if defined(__WXDEBUG__) && defined(__VISUALC__) && wxCHECK_VISUALC_VERSION(11) + if ( wxGetWinVersion() >= wxWinVersion_8 ) + { + factoryOptions.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; + } +#endif //__WXDEBUG__ + + HRESULT hr = wxDirect2D::D2D1CreateFactory( + D2D1_FACTORY_TYPE_SINGLE_THREADED, + wxIID_ID2D1Factory, + &factoryOptions, + reinterpret_cast(&gs_ID2D1Factory) + ); + wxCHECK_HRESULT_RET_PTR(hr); + } + return gs_ID2D1Factory; +} + static IDWriteFactory* gs_IDWriteFactory = NULL; IDWriteFactory* wxDWriteFactory() @@ -4457,13 +4494,9 @@ wxGraphicsRenderer* wxGraphicsRenderer::GetDirect2DRenderer() return gs_D2DRenderer; } -wxD2DRenderer::wxD2DRenderer() +wxD2DRenderer::wxD2DRenderer():m_direct2dFactory(wxD2D1Factory()) { - - HRESULT result; - result = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_direct2dFactory); - - if (FAILED(result)) + if ( m_direct2dFactory.get() == NULL ) { wxFAIL_MSG("Could not create Direct2D Factory."); } @@ -4770,6 +4803,12 @@ public: gs_D2DRenderer = NULL; } + if ( gs_ID2D1Factory ) + { + gs_ID2D1Factory->Release(); + gs_ID2D1Factory = NULL; + } + ::CoUninitialize(); } diff --git a/src/stc/PlatWX.cpp b/src/stc/PlatWX.cpp index 7d3ca2e426..0aa5a0f2a0 100644 --- a/src/stc/PlatWX.cpp +++ b/src/stc/PlatWX.cpp @@ -46,6 +46,9 @@ #include "wx/stc/stc.h" #include "wx/stc/private.h" +#if wxUSE_GRAPHICS_DIRECT2D +#include "ScintillaWX.h" +#endif Point Point::FromLong(long lpoint) { return Point(lpoint & 0xFFFF, lpoint >> 16); @@ -86,10 +89,18 @@ class wxFontWithAscent : public wxFont public: explicit wxFontWithAscent(const wxFont &font) : wxFont(font), - m_ascent(0) + m_ascent(0),m_surfaceFontData(NULL) { } + ~wxFontWithAscent() + { + if ( m_surfaceFontData ) + { + delete m_surfaceFontData; + } + } + static wxFontWithAscent* FromFID(FontID fid) { return static_cast(fid); @@ -98,8 +109,12 @@ public: void SetAscent(int ascent) { m_ascent = ascent; } int GetAscent() const { return m_ascent; } + SurfaceData* GetSurfaceFontData() const {return m_surfaceFontData;} + void SetSurfaceFontData(SurfaceData* data){m_surfaceFontData=data;} + private: int m_ascent; + SurfaceData* m_surfaceFontData; }; void SetAscent(Font& f, int ascent) @@ -149,7 +164,14 @@ void Font::Create(const FontParameters &fp) { false, stc2wx(fp.faceName), encoding); - fid = new wxFontWithAscent(font); + wxFontWithAscent* newFont = new wxFontWithAscent(font); + fid = newFont; + +#if wxUSE_GRAPHICS_DIRECT2D + if ( fp.technology == wxSTC_TECHNOLOGY_DIRECTWRITE ) { + newFont->SetSurfaceFontData(new SurfaceFontDataD2D(fp)); + } +#endif // wxUSE_GRAPHICS_DIRECT2D } @@ -674,8 +696,1176 @@ void SurfaceImpl::SetDBCSMode(int WXUNUSED(codePage)) { // dbcsMode = codePage == SC_CP_DBCS; } +#if wxUSE_GRAPHICS_DIRECT2D -Surface *Surface::Allocate(int WXUNUSED(technology)) { +//---------------------------------------------------------------------- +// SurfaceFontDataD2D + +SurfaceFontDataD2D::SurfaceFontDataD2D(const FontParameters& fp) +{ + wxCOMPtr pDWriteFactory(::wxDWriteFactory()); + + if ( pDWriteFactory.get() ) + { + wxCOMPtr pTextLayout; + wxString faceName = fp.faceName; + wxString extentTest(EXTENT_TEST); + int weight = fp.weight; + DWRITE_FONT_WEIGHT fontWeight; + DWRITE_FONT_STYLE fontStyle; + DWRITE_TEXT_METRICS textmetrics = {0,0,0,0,0,0,0,0,0}; + const int maxLines = 2; + DWRITE_LINE_METRICS lineMetrics[maxLines]; + UINT32 lineCount = 0; + FLOAT emHeight = 0; + HRESULT hr; + + if ( weight <= 100 ) + { + fontWeight = DWRITE_FONT_WEIGHT_THIN; + } + else if ( weight <= 200 ) + { + fontWeight = DWRITE_FONT_WEIGHT_EXTRA_LIGHT; + } + else if ( weight <= 300 ) + { + fontWeight = DWRITE_FONT_WEIGHT_LIGHT; + } + else if ( weight <= 350 ) + { + fontWeight = DWRITE_FONT_WEIGHT_SEMI_LIGHT; + } + else if ( weight <= 400 ) + { + fontWeight = DWRITE_FONT_WEIGHT_NORMAL; + } + else if ( weight <= 500 ) + { + fontWeight = DWRITE_FONT_WEIGHT_MEDIUM; + } + else if ( weight <= 600 ) + { + fontWeight = DWRITE_FONT_WEIGHT_SEMI_BOLD; + } + else if ( weight <= 700 ) + { + fontWeight = DWRITE_FONT_WEIGHT_BOLD; + } + else if ( weight <= 800 ) + { + fontWeight = DWRITE_FONT_WEIGHT_EXTRA_BOLD; + } + else if ( weight <= 900 ) + { + fontWeight = DWRITE_FONT_WEIGHT_HEAVY; + } + else + { + fontWeight = DWRITE_FONT_WEIGHT_EXTRA_BLACK; + } + + fontStyle = fp.italic?DWRITE_FONT_STYLE_ITALIC:DWRITE_FONT_STYLE_NORMAL; + + hr = pDWriteFactory->CreateTextFormat( + faceName.wc_str(), + NULL, + fontWeight, + fontStyle, + DWRITE_FONT_STRETCH_NORMAL, + fp.size, + L"en-us", //locale + &m_pTextFormat + ); + + if ( SUCCEEDED(hr) ) + { + m_pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); + + hr = pDWriteFactory->CreateTextLayout(extentTest.wc_str(), + extentTest.Length(), m_pTextFormat, FLT_MAX, FLT_MAX, + &pTextLayout); + } + + if ( SUCCEEDED(hr) ) + { + hr = pTextLayout->GetMetrics(&textmetrics); + } + + if ( SUCCEEDED(hr) ) + { + hr = pTextLayout->GetLineMetrics(lineMetrics, maxLines, &lineCount); + } + + if ( SUCCEEDED(hr) ) + { + hr = pTextLayout->GetFontSize(0, &emHeight); + } + + if ( SUCCEEDED(hr) ) + { + m_ascent = lineMetrics[0].baseline; + m_descent = lineMetrics[0].height - lineMetrics[0].baseline; + m_internalLeading = lineMetrics[0].height - emHeight; + m_averageCharWidth = textmetrics.width/extentTest.Length(); + + switch ( fp.extraFontFlag & wxSTC_EFF_QUALITY_MASK ) + { + case wxSTC_EFF_QUALITY_NON_ANTIALIASED: + m_aaMode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED; + break; + case wxSTC_EFF_QUALITY_ANTIALIASED: + m_aaMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; + break; + case wxSTC_EFF_QUALITY_LCD_OPTIMIZED: + m_aaMode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; + break; + default: + m_aaMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; + break; + } + + m_pTextFormat->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_UNIFORM, + lineMetrics[0].height, m_ascent); + } + else + { + m_pTextFormat.reset(); + } + } +} + +bool SurfaceFontDataD2D::Initialised() const +{ + return (m_pTextFormat.get() != NULL); +} + +//---------------------------------------------------------------------- +// SurfaceDataD2D + +SurfaceDataD2D::SurfaceDataD2D(ScintillaWX* editor):m_editor(editor), + m_pD2DFactory(::wxD2D1Factory()), m_pDWriteFactory(::wxDWriteFactory()) +{ + if( Initialised() ) + { + HRESULT hr = + m_pDWriteFactory->CreateRenderingParams(&m_defaultRenderingParams); + + if ( SUCCEEDED(hr) ) + { + unsigned int clearTypeContrast; + if ( ::SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, + &clearTypeContrast, 0) ) + { + FLOAT gamma; + if (clearTypeContrast >= 1000 && clearTypeContrast <= 2200) + gamma = static_cast(clearTypeContrast) / 1000.0f; + else + gamma = m_defaultRenderingParams->GetGamma(); + + m_pDWriteFactory->CreateCustomRenderingParams( + gamma, + m_defaultRenderingParams->GetEnhancedContrast(), + m_defaultRenderingParams->GetClearTypeLevel(), + m_defaultRenderingParams->GetPixelGeometry(), + m_defaultRenderingParams->GetRenderingMode(), + &m_customClearTypeRenderingParams); + } + } + } +} + +bool SurfaceDataD2D::Initialised() const +{ + return (m_pD2DFactory.get() != NULL && m_pDWriteFactory.get() != NULL); +} + +void SurfaceDataD2D::DiscardGraphicsResources() +{ + m_pRenderTarget.reset(); + m_pSolidBrush.reset(); + m_pPatternBrush.reset(); +} + +HRESULT SurfaceDataD2D::CreateGraphicsResources() +{ + HRESULT hr = S_OK; + if ( m_pRenderTarget.get() == NULL ) + { + D2D1_RENDER_TARGET_PROPERTIES renderTargetProperties = + D2D1::RenderTargetProperties( + D2D1_RENDER_TARGET_TYPE_DEFAULT, + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, + D2D1_ALPHA_MODE_PREMULTIPLIED)); + + hr = m_pD2DFactory->CreateDCRenderTarget( + &renderTargetProperties, + &m_pRenderTarget); + + if ( SUCCEEDED(hr) ) + { + const D2D1_COLOR_F color = D2D1::ColorF(0, 0, 0); + hr = m_pRenderTarget->CreateSolidColorBrush(color, &m_pSolidBrush); + } + + if ( SUCCEEDED(hr) ) + { + D2D1_BITMAP_BRUSH_PROPERTIES brushProperties = + D2D1::BitmapBrushProperties(D2D1_EXTEND_MODE_WRAP, + D2D1_EXTEND_MODE_WRAP, + D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR); + + wxCOMPtr bitmap; + + D2D1_PIXEL_FORMAT pixel_format = + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, + D2D1_ALPHA_MODE_PREMULTIPLIED); + + + m_pRenderTarget->CreateBitmap(D2D1::SizeU(1,1), + D2D1::BitmapProperties(pixel_format), + &bitmap); + + hr = m_pRenderTarget->CreateBitmapBrush(bitmap, brushProperties, + &m_pPatternBrush); + } + } + return hr; +} + +void SurfaceDataD2D::SetEditorPaintAbandoned() +{ + m_editor->SetPaintAbandoned(); +} + +//---------------------------------------------------------------------- +// SurfaceD2D - This is basically SurfaceD2D from the Scintilla source +// code adapted to draw in the wxMSW environment. + +class SurfaceD2D : public Surface +{ +public: + SurfaceD2D(); + virtual ~SurfaceD2D(); + + // base class virtuals + virtual void Init(WindowID wid) wxOVERRIDE; + virtual void Init(SurfaceID sid, WindowID wid) wxOVERRIDE; + virtual void InitPixMap(int width, int height, Surface *surface_, + WindowID wid) wxOVERRIDE; + + virtual void Release() wxOVERRIDE; + virtual bool Initialised() wxOVERRIDE; + virtual void PenColour(ColourDesired fore) wxOVERRIDE; + virtual int LogPixelsY() wxOVERRIDE; + virtual int DeviceHeightFont(int points) wxOVERRIDE; + virtual void MoveTo(int x_, int y_) wxOVERRIDE; + virtual void LineTo(int x_, int y_) wxOVERRIDE; + virtual void Polygon(Point *pts, int npts, ColourDesired fore, + ColourDesired back) wxOVERRIDE; + virtual void RectangleDraw(PRectangle rc, ColourDesired fore, + ColourDesired back) wxOVERRIDE; + virtual void FillRectangle(PRectangle rc, ColourDesired back) wxOVERRIDE; + virtual void FillRectangle(PRectangle rc, Surface &surfacePattern) wxOVERRIDE; + virtual void RoundedRectangle(PRectangle rc, ColourDesired fore, + ColourDesired back) wxOVERRIDE; + virtual void AlphaRectangle(PRectangle rc, int cornerSize, + ColourDesired fill, int alphaFill, + ColourDesired outline, int alphaOutline, + int flags) wxOVERRIDE; + virtual void DrawRGBAImage(PRectangle rc, int width, int height, + const unsigned char *pixelsImage) wxOVERRIDE; + virtual void Ellipse(PRectangle rc, ColourDesired fore, + ColourDesired back) wxOVERRIDE; + virtual void Copy(PRectangle rc, Point from, Surface &surfaceSource) wxOVERRIDE; + + virtual void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, + const char *s, int len, ColourDesired fore, + ColourDesired back) wxOVERRIDE; + virtual void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, + const char *s, int len, ColourDesired fore, + ColourDesired back) wxOVERRIDE; + virtual void DrawTextTransparent(PRectangle rc, Font &font_, + XYPOSITION ybase, const char *s, int len, + ColourDesired fore) wxOVERRIDE; + virtual void MeasureWidths(Font &font_, const char *s, int len, + XYPOSITION *positions) wxOVERRIDE; + virtual XYPOSITION WidthText(Font &font_, const char *s, int len) wxOVERRIDE; + virtual XYPOSITION WidthChar(Font &font_, char ch) wxOVERRIDE; + virtual XYPOSITION Ascent(Font &font_) wxOVERRIDE; + virtual XYPOSITION Descent(Font &font_) wxOVERRIDE; + virtual XYPOSITION InternalLeading(Font &font_) wxOVERRIDE; + virtual XYPOSITION ExternalLeading(Font &font_) wxOVERRIDE; + virtual XYPOSITION Height(Font &font_) wxOVERRIDE; + virtual XYPOSITION AverageCharWidth(Font &font_) wxOVERRIDE; + + virtual void SetClip(PRectangle rc) wxOVERRIDE; + virtual void FlushCachedState() wxOVERRIDE; + + virtual void SetUnicodeMode(bool unicodeMode_) wxOVERRIDE; + virtual void SetDBCSMode(int codePage) wxOVERRIDE; + + // helpers + void SetFont(Font &font_); + void SetScale(wxDC* dc); + HRESULT FlushDrawing(); + void D2DPenColour(ColourDesired fore, int alpha=255); + void DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, + const char *s, int len, UINT fuOptions); + +private: + // Private so SurfaceD2D objects can not be copied + SurfaceD2D(const SurfaceD2D &); + SurfaceD2D &operator=(const SurfaceD2D &); + + bool m_unicodeMode; + int m_x, m_y; + int m_logPixelsY; + + bool m_ownRenderTarget; + int m_clipsActive; + + XYPOSITION m_yAscent; + XYPOSITION m_yDescent; + XYPOSITION m_yInternalLeading; + XYPOSITION m_averageCharWidth; + + wxCOMPtr m_pDWriteFactory; + wxCOMPtr m_pRenderTarget; + wxCOMPtr m_pSolidBrush; + wxCOMPtr m_pPatternBrush; + wxCOMPtr m_pTextFormat; + + SurfaceDataD2D* m_surfaceData; + FontID m_curFontID; +}; + +SurfaceD2D::SurfaceD2D():m_pDWriteFactory(::wxDWriteFactory()) +{ + m_unicodeMode = false; + m_x = 0; + m_y = 0; + m_logPixelsY = 72; + + m_ownRenderTarget = false; + m_clipsActive = 0; + + m_yAscent = 2; + m_yDescent = 1; + m_yInternalLeading = 0; + m_averageCharWidth = 1; + + m_surfaceData = NULL; + m_curFontID = NULL; +} + +SurfaceD2D::~SurfaceD2D() +{ + Release(); +} + +void SurfaceD2D::Init(WindowID WXUNUSED(wid) ) +{ + Release(); + + wxScreenDC sdc; + SetScale(&sdc); +} + +void SurfaceD2D::Init(SurfaceID sid, WindowID wid) +{ + Release(); + + wxDC* dc = static_cast(sid); + wxStyledTextCtrl* stc(NULL); + ScintillaWX* sciwx(NULL); + wxWindow* win = wxDynamicCast(wid,wxWindow); + wxSize sz = dc->GetSize(); + RECT rc; + HRESULT hr; + + if ( win && win->GetName() == "wxSTCCallTip" ) + { + stc = wxDynamicCast(win->GetParent(),wxStyledTextCtrl); + } + else + { + stc = wxDynamicCast(wid,wxStyledTextCtrl); + } + + if ( stc ) + { + SetScale(dc); + sciwx = reinterpret_cast(stc->GetDirectPointer()); + m_surfaceData = static_cast(sciwx->GetSurfaceData()); + hr = m_surfaceData->CreateGraphicsResources(); + + if ( SUCCEEDED(hr) ) + { + ::SetRect(&rc,0,0,sz.GetWidth(),sz.GetHeight()); + hr = m_surfaceData->GetRenderTarget() + ->BindDC(reinterpret_cast(dc->GetHandle()),&rc); + } + + if ( SUCCEEDED(hr) ) + { + m_pRenderTarget.reset(m_surfaceData->GetRenderTarget()); + m_pSolidBrush.reset(m_surfaceData->GetSolidBrush()); + m_pPatternBrush.reset(m_surfaceData->GetPatternBrush()); + m_pRenderTarget->BeginDraw(); + } + } +} + +void SurfaceD2D::InitPixMap(int width, int height, Surface *surface_, WindowID) +{ + Release(); + + SurfaceD2D *psurfOther = static_cast(surface_); + wxCOMPtr pCompatibleRenderTarget; + D2D1_SIZE_F desiredSize = D2D1::SizeF(static_cast(width), + static_cast(height)); + D2D1_PIXEL_FORMAT desiredFormat; + +#ifdef __MINGW32__ + desiredFormat.format = DXGI_FORMAT_UNKNOWN; +#else + desiredFormat = psurfOther->m_pRenderTarget->GetPixelFormat(); +#endif + + desiredFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE; + HRESULT hr = psurfOther->m_pRenderTarget->CreateCompatibleRenderTarget( + &desiredSize, NULL, &desiredFormat, + D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE, &pCompatibleRenderTarget); + if ( SUCCEEDED(hr) ) + { + m_pRenderTarget = pCompatibleRenderTarget; + m_pRenderTarget->BeginDraw(); + m_ownRenderTarget = true; + } + SetUnicodeMode(psurfOther->m_unicodeMode); + m_logPixelsY = psurfOther->LogPixelsY(); + m_surfaceData = psurfOther->m_surfaceData; +} + +void SurfaceD2D::Release() +{ + if ( m_pRenderTarget.get() ) + { + HRESULT hr; + while ( m_clipsActive ) + { + m_pRenderTarget->PopAxisAlignedClip(); + m_clipsActive--; + } + hr = m_pRenderTarget->EndDraw(); + if ( hr == D2DERR_RECREATE_TARGET && m_surfaceData && !m_ownRenderTarget ) + { + m_surfaceData->DiscardGraphicsResources(); + m_surfaceData->SetEditorPaintAbandoned(); + } + } + + m_pRenderTarget.reset(); + m_pSolidBrush.reset(); + m_pPatternBrush.reset(); + m_pTextFormat.reset(); + m_curFontID = NULL; +} + +bool SurfaceD2D::Initialised() +{ + return m_pRenderTarget.get() != NULL; +} + +void SurfaceD2D::PenColour(ColourDesired fore) +{ + D2DPenColour(fore); +} + +int SurfaceD2D::LogPixelsY() +{ + return m_logPixelsY; +} + +int SurfaceD2D::DeviceHeightFont(int points) +{ + return ::MulDiv(points, LogPixelsY(), 72); +} + +void SurfaceD2D::MoveTo(int x_, int y_) +{ + m_x = x_; + m_y = y_; +} + +static int Delta(int difference) +{ + if ( difference < 0 ) + return -1; + else if ( difference > 0 ) + return 1; + else + return 0; +} + +static float RoundFloat(float f) +{ + return float(int(f+0.5f)); +} + +void SurfaceD2D::LineTo(int x_, int y_) +{ + if ( m_pRenderTarget.get() ) + { + int xDiff = x_ - m_x; + int xDelta = Delta(xDiff); + int yDiff = y_ - m_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(m_x, xEnd); + int width = abs(m_x - xEnd) + 1; + int yEnd = y_ - yDelta; + int top = Platform::Minimum(m_y, yEnd); + int height = abs(m_y - yEnd) + 1; + D2D1_RECT_F rectangle1 = D2D1::RectF(static_cast(left), + static_cast(top), static_cast(left+width), + static_cast(top+height)); + m_pRenderTarget->FillRectangle(&rectangle1, m_pSolidBrush); + } + else if ( (abs(xDiff) == abs(yDiff)) ) + { + // 45 degree slope + m_pRenderTarget->DrawLine(D2D1::Point2F(m_x + 0.5f, m_y + 0.5f), + D2D1::Point2F(x_ + 0.5f - xDelta, y_ + 0.5f - yDelta), + m_pSolidBrush); + } + else + { + // Line has a different slope so difficult to avoid last pixel + m_pRenderTarget->DrawLine(D2D1::Point2F(m_x + 0.5f, m_y + 0.5f), + D2D1::Point2F(x_ + 0.5f, y_ + 0.5f), m_pSolidBrush); + } + m_x = x_; + m_y = y_; + } +} + +void SurfaceD2D::Polygon(Point *pts, int npts, ColourDesired fore, + ColourDesired back) +{ + if ( m_pRenderTarget.get() ) + { + wxCOMPtr pFactory; + wxCOMPtr geometry; + wxCOMPtr sink; + + m_pRenderTarget->GetFactory(&pFactory); + + HRESULT hr = pFactory->CreatePathGeometry(&geometry); + if ( SUCCEEDED(hr) ) + { + 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(); + + D2DPenColour(back); + m_pRenderTarget->FillGeometry(geometry,m_pSolidBrush); + D2DPenColour(fore); + m_pRenderTarget->DrawGeometry(geometry,m_pSolidBrush); + } + } +} + +void SurfaceD2D::RectangleDraw(PRectangle rc, ColourDesired fore, + ColourDesired back) +{ + if ( m_pRenderTarget.get() ) + { + D2D1_RECT_F rectangle1 = D2D1::RectF(RoundFloat(rc.left) + 0.5f, + rc.top+0.5f, RoundFloat(rc.right) - 0.5f, rc.bottom-0.5f); + D2DPenColour(back); + m_pRenderTarget->FillRectangle(&rectangle1, m_pSolidBrush); + D2DPenColour(fore); + m_pRenderTarget->DrawRectangle(&rectangle1, m_pSolidBrush); + } +} + +void SurfaceD2D::FillRectangle(PRectangle rc, ColourDesired back) +{ + if ( m_pRenderTarget.get() ) + { + D2DPenColour(back); + D2D1_RECT_F rectangle1 = D2D1::RectF(RoundFloat(rc.left), rc.top, + RoundFloat(rc.right), rc.bottom); + m_pRenderTarget->FillRectangle(&rectangle1, m_pSolidBrush); + } +} + +void SurfaceD2D::FillRectangle(PRectangle rc, Surface &surfacePattern) +{ + SurfaceD2D &surfOther = static_cast(surfacePattern); + surfOther.FlushDrawing(); + + wxCOMPtr pBitmap; + wxCOMPtr pCompatibleRenderTarget( + reinterpret_cast( + surfOther.m_pRenderTarget.get())); + + HRESULT hr = pCompatibleRenderTarget->GetBitmap(&pBitmap); + + if ( SUCCEEDED(hr) ) + { + if ( m_pPatternBrush.get() ) + { + m_pPatternBrush->SetBitmap(pBitmap); + } + else + { + D2D1_BITMAP_BRUSH_PROPERTIES brushProperties = + D2D1::BitmapBrushProperties(D2D1_EXTEND_MODE_WRAP, + D2D1_EXTEND_MODE_WRAP, + D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR); + + hr = m_pRenderTarget->CreateBitmapBrush(pBitmap, brushProperties, + &m_pPatternBrush); + } + } + + if ( SUCCEEDED(hr) ) + { + m_pRenderTarget->FillRectangle( + D2D1::RectF(rc.left, rc.top, rc.right, rc.bottom), + m_pPatternBrush); + } +} + +void SurfaceD2D::RoundedRectangle(PRectangle rc, ColourDesired fore, + ColourDesired back) +{ + if ( m_pRenderTarget.get() ) + { + D2D1_ROUNDED_RECT roundedRectFill = { + D2D1::RectF(rc.left+1.0f, rc.top+1.0f, rc.right-1.0f, rc.bottom-1.0f), + 4, 4}; + D2DPenColour(back); + m_pRenderTarget->FillRoundedRectangle(roundedRectFill, m_pSolidBrush); + + D2D1_ROUNDED_RECT roundedRect = { + D2D1::RectF(rc.left + 0.5f, rc.top+0.5f, rc.right - 0.5f, rc.bottom-0.5f), + 4, 4}; + D2DPenColour(fore); + m_pRenderTarget->DrawRoundedRectangle(roundedRect, m_pSolidBrush); + } +} + +void SurfaceD2D::AlphaRectangle(PRectangle rc, int cornerSize, + ColourDesired fill, int alphaFill, + ColourDesired outline, int alphaOutline, + int /* flags*/ ) +{ + if ( m_pRenderTarget.get() ) + { + if (cornerSize == 0) + { + // When corner size is zero, draw square rectangle to prevent + // blurry pixels at corners + D2D1_RECT_F rectFill = D2D1::RectF(RoundFloat(rc.left) + 1.0f, + rc.top + 1.0f, RoundFloat(rc.right) - 1.0f, rc.bottom - 1.0f); + D2DPenColour(fill, alphaFill); + m_pRenderTarget->FillRectangle(rectFill, m_pSolidBrush); + + D2D1_RECT_F rectOutline = D2D1::RectF(RoundFloat(rc.left) + 0.5f, + rc.top + 0.5f, RoundFloat(rc.right) - 0.5f, rc.bottom - 0.5f); + D2DPenColour(outline, alphaOutline); + m_pRenderTarget->DrawRectangle(rectOutline, m_pSolidBrush); + } + else + { + const float cornerSizeF = static_cast(cornerSize); + D2D1_ROUNDED_RECT roundedRectFill = { + D2D1::RectF(RoundFloat(rc.left) + 1.0f, rc.top + 1.0f, + RoundFloat(rc.right) - 1.0f, rc.bottom - 1.0f), + cornerSizeF, cornerSizeF}; + D2DPenColour(fill, alphaFill); + m_pRenderTarget->FillRoundedRectangle(roundedRectFill, m_pSolidBrush); + + D2D1_ROUNDED_RECT roundedRect = { + D2D1::RectF(RoundFloat(rc.left) + 0.5f, rc.top + 0.5f, + RoundFloat(rc.right) - 0.5f, rc.bottom - 0.5f), + cornerSizeF, cornerSizeF}; + D2DPenColour(outline, alphaOutline); + m_pRenderTarget->DrawRoundedRectangle(roundedRect, m_pSolidBrush); + } + } +} + +void SurfaceD2D::DrawRGBAImage(PRectangle rc, int width, int height, + const unsigned char *pixelsImage) +{ + if ( m_pRenderTarget.get() ) + { + if (rc.Width() > width) + rc.left += static_cast((rc.Width() - width) / 2); + rc.right = rc.left + width; + if (rc.Height() > height) + rc.top += static_cast((rc.Height() - height) / 2); + rc.bottom = rc.top + height; + + wxVector image(height * width * 4); + for ( int yPixel=0; yPixel bitmap; + 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 = m_pRenderTarget->CreateBitmap(size, &image[0], + width * 4, &props, &bitmap); + + if ( SUCCEEDED(hr) ) + { + D2D1_RECT_F rcDestination = {rc.left, rc.top, rc.right, rc.bottom}; + m_pRenderTarget->DrawBitmap(bitmap, rcDestination); + } + } +} + +void SurfaceD2D::Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back) +{ + if ( m_pRenderTarget.get() ) + { + FLOAT radius = rc.Width() / 2.0f; + D2D1_ELLIPSE ellipse = { + D2D1::Point2F((rc.left + rc.right) / 2.0f, + (rc.top + rc.bottom) / 2.0f), + radius, radius}; + + PenColour(back); + m_pRenderTarget->FillEllipse(ellipse, m_pSolidBrush); + PenColour(fore); + m_pRenderTarget->DrawEllipse(ellipse, m_pSolidBrush); + } +} + +void SurfaceD2D::Copy(PRectangle rc, Point from, Surface &surfaceSource) { + SurfaceD2D &surfOther = static_cast(surfaceSource); + surfOther.FlushDrawing(); + + wxCOMPtr pBitmap; + wxCOMPtr pCompatibleRenderTarget( + reinterpret_cast(surfOther.m_pRenderTarget.get())); + + 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()}; + m_pRenderTarget->DrawBitmap(pBitmap, rcDestination, 1.0f, + D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR, rcSource); + + hr = m_pRenderTarget->Flush(); + if ( FAILED(hr) ) + { + Platform::DebugPrintf("Failed Flush 0x%x\n", hr); + } + } +} + +void SurfaceD2D::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, + const char *s, int len, ColourDesired fore, + ColourDesired back) +{ + if ( m_pRenderTarget.get() ) + { + FillRectangle(rc, back); + D2DPenColour(fore); + DrawTextCommon(rc, font_, ybase, s, len, ETO_OPAQUE); + } +} + +void SurfaceD2D::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, + const char *s, int len, ColourDesired fore, + ColourDesired back) +{ + if ( m_pRenderTarget.get() ) + { + FillRectangle(rc, back); + D2DPenColour(fore); + DrawTextCommon(rc, font_, ybase, s, len, ETO_OPAQUE | ETO_CLIPPED); + } +} + +void SurfaceD2D::DrawTextTransparent(PRectangle rc, Font &font_, + XYPOSITION ybase, const char *s, int len, + ColourDesired fore) +{ + // Avoid drawing spaces in transparent mode + for ( int i=0; i pTextLayout; + DWRITE_TEXT_METRICS textMetrics = {0,0,0,0,0,0,0,0,0}; + + HRESULT hr = m_pDWriteFactory->CreateTextLayout(tbuf.wc_str(), + tbuf.Length(), m_pTextFormat, FLT_MAX, FLT_MAX, &pTextLayout); + + if ( SUCCEEDED(hr) ) + { + hr = pTextLayout->GetMetrics(&textMetrics); + } + + if ( SUCCEEDED(hr) ) + { + width = textMetrics.widthIncludingTrailingWhitespace; + } + } + return width; +} + +void SurfaceD2D::MeasureWidths(Font &font_, const char *s, int len, + XYPOSITION *positions) +{ + int fit = 0; + wxString tbuf = stc2wx(s,len); + wxVector poses; + poses.reserve(tbuf.Length()); + poses.resize(tbuf.Length()); + + fit = tbuf.Length(); + const int clusters = 1000; + DWRITE_CLUSTER_METRICS clusterMetrics[clusters]; + UINT32 count = 0; + SetFont(font_); + + if ( m_pDWriteFactory.get() && m_pTextFormat.get() ) + { + wxCOMPtr pTextLayout; + + HRESULT hr = m_pDWriteFactory->CreateTextLayout(tbuf.wc_str(), + tbuf.Length(), m_pTextFormat, FLT_MAX, FLT_MAX, &pTextLayout); + if ( !SUCCEEDED(hr) ) + return; + + hr = pTextLayout->GetClusterMetrics(clusterMetrics, clusters, &count); + if ( !SUCCEEDED(hr) ) + return; + + // A cluster may be more than one WCHAR, such as for "ffi" which is a + // ligature in the Candara font + FLOAT position = 0.0f; + size_t ti=0; + for ( size_t ci=0; ci(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(len); kk++ ) + { + positions[kk] = poses[kk]; + } + } +} + +XYPOSITION SurfaceD2D::WidthChar(Font &font_, char ch) +{ + FLOAT width = 1.0; + SetFont(font_); + if ( m_pDWriteFactory.get() && m_pTextFormat.get() ) + { + wxCOMPtr pTextLayout; + const WCHAR wch = ch; + HRESULT hr = m_pDWriteFactory->CreateTextLayout(&wch, 1, m_pTextFormat, + 1000.0, 1000.0, &pTextLayout); + + if ( SUCCEEDED(hr) ) + { + DWRITE_TEXT_METRICS textMetrics; + if (SUCCEEDED(pTextLayout->GetMetrics(&textMetrics))) + width = textMetrics.widthIncludingTrailingWhitespace; + } + } + return width; +} + +XYPOSITION SurfaceD2D::Ascent(Font &font_) +{ + SetFont(font_); + return ceil(m_yAscent); +} + +XYPOSITION SurfaceD2D::Descent(Font &font_) +{ + SetFont(font_); + return ceil(m_yDescent); +} + +XYPOSITION SurfaceD2D::InternalLeading(Font &font_) +{ + SetFont(font_); + return floor(m_yInternalLeading); +} + +XYPOSITION SurfaceD2D::ExternalLeading(Font &) +{ + // Not implemented, always return one + return 1; +} + +XYPOSITION SurfaceD2D::Height(Font &font_) +{ + return Ascent(font_) + Descent(font_); +} + +XYPOSITION SurfaceD2D::AverageCharWidth(Font &font_) +{ + SetFont(font_); + return m_averageCharWidth; +} + +void SurfaceD2D::SetClip(PRectangle rc) +{ + if ( m_pRenderTarget.get() ) + { + D2D1_RECT_F rcClip = {rc.left, rc.top, rc.right, rc.bottom}; + m_pRenderTarget->PushAxisAlignedClip(rcClip, D2D1_ANTIALIAS_MODE_ALIASED); + m_clipsActive++; + } +} + +void SurfaceD2D::FlushCachedState() +{ +} + +void SurfaceD2D::SetUnicodeMode(bool unicodeMode_) +{ + m_unicodeMode=unicodeMode_; +} + +void SurfaceD2D::SetDBCSMode(int WXUNUSED(codePage_)) +{ +} + +void SurfaceD2D::SetFont(Font &font_) +{ + FontID id = font_.GetID(); + + if (m_curFontID != id) + { + wxFontWithAscent *pfm = static_cast(id); + SurfaceFontDataD2D* sfd = + static_cast(pfm->GetSurfaceFontData()); + + if ( sfd->Initialised() ) + { + m_pTextFormat.reset(sfd->GetFormat()); + m_yAscent = sfd->GetAscent(); + m_yDescent = sfd->GetDescent(); + m_yInternalLeading = sfd->GetInternalLeading(); + m_averageCharWidth = sfd->GetAverageCharWidth(); + + if ( m_pRenderTarget.get() ) + { + D2D1_TEXT_ANTIALIAS_MODE aaMode = sfd->GetFontQuality(); + + if ( m_surfaceData && m_surfaceData->Initialised() ) + { + if ( aaMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE ) + { + m_pRenderTarget->SetTextRenderingParams( + m_surfaceData->GetCustomClearTypeRenderingParams()); + } + else + { + m_pRenderTarget->SetTextRenderingParams( + m_surfaceData->GetDefaultRenderingParams()); + } + } + + m_pRenderTarget->SetTextAntialiasMode(aaMode); + } + + m_curFontID = id; + } + } +} + +void SurfaceD2D::SetScale(wxDC* dc) +{ + wxSize sz = dc->GetPPI(); + m_logPixelsY = sz.GetY(); +} + +HRESULT SurfaceD2D::FlushDrawing() +{ + return m_pRenderTarget->Flush(); +} + +void SurfaceD2D::D2DPenColour(ColourDesired fore, int alpha) +{ + if ( m_pRenderTarget.get() ) + { + D2D_COLOR_F col; + col.r = (fore.AsLong() & 0xff) / 255.0f; + col.g = ((fore.AsLong() & 0xff00) >> 8) / 255.0f; + col.b = (fore.AsLong() >> 16) / 255.0f; + col.a = alpha / 255.0f; + if ( m_pSolidBrush.get() ) + { + m_pSolidBrush->SetColor(col); + } + else + { + HRESULT hr = m_pRenderTarget->CreateSolidColorBrush(col, &m_pSolidBrush); + if ( !SUCCEEDED(hr) ) + { + m_pSolidBrush.reset(); + } + } + } +} + +void SurfaceD2D::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, + const char *s, int len, UINT fuOptions) +{ + SetFont(font_); + + if ( m_pRenderTarget.get() && m_pSolidBrush.get() && m_pTextFormat.get() ) + { + // Explicitly creating a text layout appears a little faster + wxCOMPtr pTextLayout; + wxString tbuf = stc2wx(s, len); + HRESULT hr; + + if ( fuOptions & ETO_CLIPPED ) + { + D2D1_RECT_F rcClip = {rc.left, rc.top, rc.right, rc.bottom}; + m_pRenderTarget->PushAxisAlignedClip(rcClip, + D2D1_ANTIALIAS_MODE_ALIASED); + } + + hr = m_pDWriteFactory->CreateTextLayout(tbuf.wc_str(), tbuf.Length(), + m_pTextFormat, rc.Width(), rc.Height(), &pTextLayout); + + if ( SUCCEEDED(hr) ) + { + D2D1_POINT_2F origin = {rc.left, ybase-m_yAscent}; + m_pRenderTarget->DrawTextLayout(origin, pTextLayout, m_pSolidBrush, + D2D1_DRAW_TEXT_OPTIONS_NONE); + } + + if ( fuOptions & ETO_CLIPPED ) + { + m_pRenderTarget->PopAxisAlignedClip(); + } + } +} + +#endif // wxUSE_GRAPHICS_DIRECT2D + +Surface *Surface::Allocate(int technology) { +#if wxUSE_GRAPHICS_DIRECT2D + if ( technology == wxSTC_TECHNOLOGY_DIRECTWRITE ) { + return new SurfaceD2D; + } +#endif // wxUSE_GRAPHICS_DIRECT2D return new SurfaceImpl; } diff --git a/src/stc/PlatWX.h b/src/stc/PlatWX.h index ac762ddf8e..a2a86da45b 100644 --- a/src/stc/PlatWX.h +++ b/src/stc/PlatWX.h @@ -6,3 +6,69 @@ wxRect wxRectFromPRectangle(PRectangle prc); PRectangle PRectangleFromwxRect(wxRect rc); wxColour wxColourFromCD(const ColourDesired& ca); +class SurfaceData +{ + public: + virtual ~SurfaceData(){} +}; + +#if wxUSE_GRAPHICS_DIRECT2D + +#include +#include + +class ScintillaWX; + +class SurfaceDataD2D: public SurfaceData +{ + public: + SurfaceDataD2D(ScintillaWX*); + bool Initialised() const; + void DiscardGraphicsResources(); + HRESULT CreateGraphicsResources(); + void SetEditorPaintAbandoned(); + + ID2D1DCRenderTarget* GetRenderTarget() const {return m_pRenderTarget.get();} + ID2D1SolidColorBrush* GetSolidBrush() const {return m_pSolidBrush.get();} + ID2D1BitmapBrush* GetPatternBrush() const {return m_pPatternBrush.get();} + IDWriteRenderingParams* GetDefaultRenderingParams() const + {return m_defaultRenderingParams;} + IDWriteRenderingParams* GetCustomClearTypeRenderingParams() const + {return m_customClearTypeRenderingParams;} + + private: + wxCOMPtr m_pD2DFactory; + wxCOMPtr m_pDWriteFactory; + wxCOMPtr m_pRenderTarget; + wxCOMPtr m_pSolidBrush; + wxCOMPtr m_pPatternBrush; + wxCOMPtr m_defaultRenderingParams; + wxCOMPtr m_customClearTypeRenderingParams; + + ScintillaWX* m_editor; +}; + +class SurfaceFontDataD2D: public SurfaceData +{ + public: + SurfaceFontDataD2D(const FontParameters& fp); + bool Initialised() const; + + XYPOSITION GetAscent() const {return m_ascent;} + XYPOSITION GetDescent() const {return m_descent;} + XYPOSITION GetInternalLeading() const {return m_internalLeading;} + XYPOSITION GetAverageCharWidth() const {return m_averageCharWidth;} + + D2D1_TEXT_ANTIALIAS_MODE GetFontQuality() const {return m_aaMode;} + IDWriteTextFormat* GetFormat() const {return m_pTextFormat.get();} + + private: + XYPOSITION m_ascent; + XYPOSITION m_descent; + XYPOSITION m_internalLeading; + XYPOSITION m_averageCharWidth; + D2D1_TEXT_ANTIALIAS_MODE m_aaMode; + wxCOMPtr m_pTextFormat; +}; + +#endif // wxUSE_GRAPHICS_DIRECT2D diff --git a/src/stc/ScintillaWX.cpp b/src/stc/ScintillaWX.cpp index deaacadbfe..ba6b2641e5 100644 --- a/src/stc/ScintillaWX.cpp +++ b/src/stc/ScintillaWX.cpp @@ -118,6 +118,7 @@ public: m_ct(ct), m_swx(swx), m_cx(wxDefaultCoord), m_cy(wxDefaultCoord) { SetBackgroundStyle(wxBG_STYLE_CUSTOM); + SetName("wxSTCCallTip"); } ~wxSTCCallTip() { @@ -134,7 +135,7 @@ public: void OnPaint(wxPaintEvent& WXUNUSED(evt)) { wxAutoBufferedPaintDC dc(this); - Surface* surfaceWindow = Surface::Allocate(0); + Surface* surfaceWindow = Surface::Allocate(m_swx->technology); surfaceWindow->Init(&dc, m_ct->wDraw.GetID()); m_ct->PaintCT(surfaceWindow); surfaceWindow->Release(); @@ -270,6 +271,8 @@ ScintillaWX::ScintillaWX(wxStyledTextCtrl* win) { timers[tickScroll] = new wxSTCTimer(this,tickScroll); timers[tickWiden] = new wxSTCTimer(this,tickWiden); timers[tickDwell] = new wxSTCTimer(this,tickDwell); + + m_surfaceData = NULL; } @@ -278,6 +281,11 @@ ScintillaWX::~ScintillaWX() { delete i->second; } timers.clear(); + + if ( m_surfaceData != NULL ) { + delete m_surfaceData; + } + Finalise(); } @@ -817,6 +825,36 @@ sptr_t ScintillaWX::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) } #endif +#if wxUSE_GRAPHICS_DIRECT2D + case SCI_SETTECHNOLOGY: + if ((wParam == SC_TECHNOLOGY_DEFAULT) || (wParam == SC_TECHNOLOGY_DIRECTWRITE)) { + if (technology != static_cast(wParam)) { + SurfaceDataD2D* newSurfaceData(NULL); + + if (static_cast(wParam) > SC_TECHNOLOGY_DEFAULT) { + newSurfaceData = new SurfaceDataD2D(this); + + if (!newSurfaceData->Initialised()) { + // Failed to load Direct2D or DirectWrite so no effect + delete newSurfaceData; + return 0; + } + } + + technology = static_cast(wParam); + if ( m_surfaceData ) { + delete m_surfaceData; + } + m_surfaceData = newSurfaceData; + + // Invalidate all cached information including layout. + DropGraphics(true); + InvalidateStyleRedraw(); + } + } + break; +#endif + #ifdef SCI_LEXER case SCI_LOADLEXERLIBRARY: LexerManager::GetInstance()->Load((const char*)lParam); diff --git a/src/stc/ScintillaWX.h b/src/stc/ScintillaWX.h index 6ab764c5f3..d4d03f9c0e 100644 --- a/src/stc/ScintillaWX.h +++ b/src/stc/ScintillaWX.h @@ -87,6 +87,7 @@ class WXDLLIMPEXP_FWD_CORE wxDC; class WXDLLIMPEXP_FWD_STC wxStyledTextCtrl; // forward class ScintillaWX; class wxSTCTimer; +class SurfaceData; //---------------------------------------------------------------------- // Helper classes @@ -196,6 +197,8 @@ public: void ClipChildren(wxDC& dc, PRectangle rect); void SetUseAntiAliasing(bool useAA); bool GetUseAntiAliasing(); + SurfaceData* GetSurfaceData() const {return m_surfaceData;} + void SetPaintAbandoned(){paintState = paintAbandoned;} private: bool capturedMouse; @@ -212,6 +215,7 @@ private: int wheelVRotation; int wheelHRotation; + SurfaceData* m_surfaceData; // For use in creating a system caret bool HasCaretSizeChanged(); diff --git a/src/stc/gen_docs.py b/src/stc/gen_docs.py index 949040e8e3..c66ff27f77 100644 --- a/src/stc/gen_docs.py +++ b/src/stc/gen_docs.py @@ -517,6 +517,7 @@ docsMap = { 'SetMouseDwellTime':'Notifications', 'GetBufferedDraw':'OtherSettings', 'GetCodePage':'OtherSettings', + 'GetFontQuality':'OtherSettings', 'GetFocus':'OtherSettings', 'GetIMEInteraction':'OtherSettings', 'GetPhasesDraw':'OtherSettings', @@ -525,6 +526,7 @@ docsMap = { 'SetBufferedDraw':'OtherSettings', 'SetCodePage':'OtherSettings', 'SetFocus':'OtherSettings', + 'SetFontQuality':'OtherSettings', 'SetIMEInteraction':'OtherSettings', 'SetLayoutCache':'OtherSettings', 'SetPhasesDraw':'OtherSettings', @@ -840,7 +842,9 @@ docSubstitutions = { 'SetSelectionMode':{'SC_SEL_STREAM':'wxSTC_SEL_STREAM', 'SC_SEL_RECTANGLE':'wxSTC_SEL_RECTANGLE','SC_SEL_THIN':'wxSTC_SEL_THIN', - 'SC_SEL_LINES':'wxSTC_SEL_LINES'} + 'SC_SEL_LINES':'wxSTC_SEL_LINES'}, + + 'SetFontQuality':{' from the FontQuality enumeration':''} } @@ -1033,10 +1037,24 @@ extendedDocs = { '@endlink constants.',), 'SetTechnology': - ('The input should be one of the', - '@link wxStyledTextCtrl::wxSTC_TECHNOLOGY_DEFAULT wxSTC_TECHNOLOGY_* ' + ('@remarks', + 'For the wxMSW port, the input can be either wxSTC_TECHNOLOGY_DEFAULT', + 'or wxSTC_TECHNOLOGY_DIRECTWRITE. With other ports, this method has', + 'no effect.',), + + 'GetFontQuality': + ('The return value will be one of the', + '@link wxStyledTextCtrl::wxSTC_EFF_QUALITY_DEFAULT wxSTC_EFF_QUALITY_* ' '@endlink constants.',), + 'SetFontQuality': + ('The input should be one of the', + '@link wxStyledTextCtrl::wxSTC_EFF_QUALITY_DEFAULT wxSTC_EFF_QUALITY_* ' + '@endlink constants.', + '@remarks', + 'This method only has any effect with the wxMSW port and when', + 'technology has been set to wxSTC_TECHNOLOGY_DIRECTWRITE.',), + 'GetIMEInteraction': ('The return value will be one of the', '@link wxStyledTextCtrl::wxSTC_IME_WINDOWED wxSTC_IME_* @endlink constants.',), @@ -1362,6 +1380,7 @@ sinceAnnotations= { 'FoldDisplayTextSetStyle':'3.1.1', 'GetDirectFunction':'3.1.1', 'GetDirectPointer':'3.1.1', + 'GetFontQuality':'3.1.1', 'GetIdleStyling':'3.1.1', 'GetLexerLanguage':'3.1.1', 'GetMarginBackN':'3.1.1', @@ -1374,6 +1393,7 @@ sinceAnnotations= { 'MultiEdgeClearAll':'3.1.1', 'MultipleSelectAddEach':'3.1.1', 'MultipleSelectAddNext':'3.1.1', + 'SetFontQuality':'3.1.1', 'SetIdleStyling':'3.1.1', 'SetMarginBackN':'3.1.1', 'SetMargins':'3.1.1', diff --git a/src/stc/gen_iface.py b/src/stc/gen_iface.py index cbba253924..deabf2962b 100755 --- a/src/stc/gen_iface.py +++ b/src/stc/gen_iface.py @@ -895,8 +895,6 @@ methodOverrideMap = { return stc2wx(buf);''' ), - 'SetFontQuality' : (None, 0, 0), - 'GetFontQuality' : (None, 0, 0), 'SetSelection' : (None, 0, 0), 'GetCharacterPointer' : (0, diff --git a/src/stc/stc.cpp b/src/stc/stc.cpp index 79b83ca1f5..b4602db8da 100644 --- a/src/stc/stc.cpp +++ b/src/stc/stc.cpp @@ -231,6 +231,10 @@ bool wxStyledTextCtrl::Create(wxWindow *parent, SetBufferedDraw(true); #endif +#if wxUSE_GRAPHICS_DIRECT2D + SetFontQuality(wxSTC_EFF_QUALITY_DEFAULT); +#endif + return true; } @@ -2533,6 +2537,18 @@ void wxStyledTextCtrl::SetPhasesDraw(int phases) SendMsg(SCI_SETPHASESDRAW, phases, 0); } +// Choose the quality level for text. +void wxStyledTextCtrl::SetFontQuality(int fontQuality) +{ + SendMsg(SCI_SETFONTQUALITY, fontQuality, 0); +} + +// Retrieve the quality level for text. +int wxStyledTextCtrl::GetFontQuality() const +{ + return SendMsg(SCI_GETFONTQUALITY, 0, 0); +} + // Scroll so that a display line is at the top of the display. void wxStyledTextCtrl::SetFirstVisibleLine(int displayLine) { diff --git a/src/stc/stc.cpp.in b/src/stc/stc.cpp.in index fc3c80485f..d4af95790c 100644 --- a/src/stc/stc.cpp.in +++ b/src/stc/stc.cpp.in @@ -231,6 +231,10 @@ bool wxStyledTextCtrl::Create(wxWindow *parent, SetBufferedDraw(true); #endif +#if wxUSE_GRAPHICS_DIRECT2D + SetFontQuality(wxSTC_EFF_QUALITY_DEFAULT); +#endif + return true; }