<ClCompile Include="..\editlib\basic.cpp" />\r
<ClCompile Include="..\editlib\batch.cpp" />\r
<ClCompile Include="..\editlib\ccrystaleditview.cpp" />\r
+ <ClCompile Include="..\editlib\ccrystalrendererdirectdraw.cpp" />\r
+ <ClCompile Include="..\editlib\ccrystalrenderergdi.cpp" />\r
<ClCompile Include="..\editlib\ccrystaltextbuffer.cpp" />\r
<ClCompile Include="..\editlib\ccrystaltextmarkers.cpp" />\r
<ClCompile Include="..\editlib\ccrystaltextview.cpp" />\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="..\editlib\ccrystaleditview.h" />\r
+ <ClInclude Include="..\editlib\ccrystalrenderer.h" />\r
+ <ClInclude Include="..\editlib\ccrystalrendererdirectdraw.h" />\r
+ <ClInclude Include="..\editlib\ccrystalrenderergdi.h" />\r
<ClInclude Include="..\editlib\ccrystaltextbuffer.h" />\r
<ClInclude Include="..\editlib\ccrystaltextmarkers.h" />\r
<ClInclude Include="..\editlib\ccrystaltextview.h" />\r
<ClCompile Include="..\editlib\icu.cpp">\r
<Filter>editlib</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\editlib\ccrystalrendererdirectdraw.cpp">\r
+ <Filter>editlib</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\editlib\ccrystalrenderergdi.cpp">\r
+ <Filter>editlib</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
<ResourceCompile Include="Sample.rc">\r
<ClInclude Include="..\editlib\icu.hpp">\r
<Filter>editlib</Filter>\r
</ClInclude>\r
+ <ClInclude Include="..\editlib\ccrystalrenderer.h">\r
+ <Filter>editlib</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\editlib\ccrystalrendererdirectdraw.h">\r
+ <Filter>editlib</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\editlib\ccrystalrenderergdi.h">\r
+ <Filter>editlib</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<Image Include="res\mg_icons.bmp">\r
<ClCompile Include="..\editlib\basic.cpp" />
<ClCompile Include="..\editlib\batch.cpp" />
<ClCompile Include="..\editlib\ccrystaleditview.cpp" />
+ <ClCompile Include="..\editlib\ccrystalrendererdirectdraw.cpp" />
+ <ClCompile Include="..\editlib\ccrystalrenderergdi.cpp" />
<ClCompile Include="..\editlib\ccrystaltextbuffer.cpp" />
<ClCompile Include="..\editlib\ccrystaltextmarkers.cpp" />
<ClCompile Include="..\editlib\ccrystaltextview.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\editlib\ccrystaleditview.h" />
+ <ClInclude Include="..\editlib\ccrystalrenderer.h" />
+ <ClInclude Include="..\editlib\ccrystalrendererdirectdraw.h" />
+ <ClInclude Include="..\editlib\ccrystalrenderergdi.h" />
<ClInclude Include="..\editlib\ccrystaltextbuffer.h" />
<ClInclude Include="..\editlib\ccrystaltextmarkers.h" />
<ClInclude Include="..\editlib\ccrystaltextview.h" />
<ClCompile Include="..\editlib\icu.cpp">
<Filter>editlib</Filter>
</ClCompile>
+ <ClCompile Include="..\editlib\ccrystalrendererdirectdraw.cpp">
+ <Filter>editlib</Filter>
+ </ClCompile>
+ <ClCompile Include="..\editlib\ccrystalrenderergdi.cpp">
+ <Filter>editlib</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Sample.rc">
<ClInclude Include="..\editlib\icu.hpp">
<Filter>editlib</Filter>
</ClInclude>
+ <ClInclude Include="..\editlib\ccrystalrenderer.h">
+ <Filter>editlib</Filter>
+ </ClInclude>
+ <ClInclude Include="..\editlib\ccrystalrendererdirectdraw.h">
+ <Filter>editlib</Filter>
+ </ClInclude>
+ <ClInclude Include="..\editlib\ccrystalrenderergdi.h">
+ <Filter>editlib</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="res\mg_icons.bmp">
--- /dev/null
+/**
+ * @file ccrystalrenderer.h
+ *
+ * @brief Declaration file for CCrystalRenderer
+ */
+
+#pragma once
+
+////////////////////////////////////////////////////////////////////////////
+// Forward class declarations
+
+
+////////////////////////////////////////////////////////////////////////////
+// CCrystalRenderer class declaration
+
+
+struct CCrystalRenderer
+{
+ /** @brief Width of icons printed in the margin. */
+ static const UINT MARGIN_ICON_WIDTH = 12;
+ /** @brief Height of icons printed in the margin. */
+ static const UINT MARGIN_ICON_HEIGHT = 12;
+
+ virtual ~CCrystalRenderer() {};
+
+ virtual void BindDC(const CDC& dc, const CRect& rc) = 0;
+ virtual void BeginDraw() = 0;
+ virtual bool EndDraw() = 0;
+ virtual void SetFont(const LOGFONT &lf) = 0;
+ virtual void SwitchFont(bool italic, bool bold) = 0;
+ virtual CSize GetCharWidthHeight() = 0;
+ virtual bool GetCharWidth(unsigned start, unsigned end, int *nWidthArray) = 0;
+ virtual void SetTextColor(COLORREF clr) = 0;
+ virtual void SetBkColor(COLORREF clr) = 0;
+ virtual void DrawText(int x, int y, const CRect &rc, const TCHAR *text, size_t len, const int nWidths[]) = 0;
+ virtual void FillRectangle(const CRect &rc) = 0;
+ virtual void FillSolidRectangle(const CRect &rc, COLORREF color) = 0;
+ virtual void DrawRoundRectangle(int left, int top , int right, int bottom, int width, int height) = 0;
+ virtual void PushAxisAlignedClip(const CRect &rc) = 0;
+ virtual void PopAxisAlignedClip() = 0;
+ virtual void DrawMarginIcon(int x, int y, int iconIndex) = 0;
+ virtual void DrawMarginLineNumber(int x, int y, int number) = 0;
+ virtual void DrawBoundaryLine(int left, int right, int y) = 0;
+ virtual void DrawLineCursor(int left, int right, int y, int height) = 0;
+};
+
--- /dev/null
+/**
+ * @file ccrystalrendererdirectdraw.cpp
+ *
+ * @brief Implementation of the CCrystalRendererDirectWrite class
+ */
+
+#ifdef _WIN64
+#undef WINVER
+#define WINVER 0x0a00
+#include <afxwin.h>
+#include "ccrystalrendererdirectwrite.h"
+#include "resource.h"
+#include <d2d1_3.h>
+#include <dwrite_3.h>
+#include <vector>
+#include <algorithm>
+#include <utility>
+
+struct CustomGlyphRun : public DWRITE_GLYPH_RUN
+{
+ CustomGlyphRun(const DWRITE_GLYPH_RUN& glyphRun, float charWidth = 0, float charHeight = 0)
+ : DWRITE_GLYPH_RUN(glyphRun)
+ , sumCharWidth(0)
+ {
+ float minScale = 1.0f;
+ glyphAdvances = new float[glyphCount];
+ std::vector<DWRITE_GLYPH_METRICS> glyphMetrics(glyphCount);
+ glyphRun.fontFace->GetDesignGlyphMetrics(glyphIndices, glyphCount, glyphMetrics.data(), isSideways);
+ DWRITE_FONT_METRICS fontFaceMetrics;
+ glyphRun.fontFace->GetMetrics(&fontFaceMetrics);
+ for (unsigned i = 0; i < glyphCount; ++i)
+ {
+ const_cast<float*>(glyphAdvances)[i] = static_cast<int>(charWidth)
+ * ((charWidth < glyphRun.glyphAdvances[i]) ? 2.0f : 1.0f);
+ sumCharWidth += glyphAdvances[i];
+ float scaleX = glyphAdvances[i] / glyphRun.glyphAdvances[i];
+ if (minScale > scaleX)
+ minScale = scaleX;
+
+ float height = (glyphMetrics[i].advanceHeight - glyphMetrics[i].topSideBearing - glyphMetrics[i].bottomSideBearing)
+ * glyphRun.fontEmSize / fontFaceMetrics.designUnitsPerEm;
+ float scaleY = charHeight / height;
+ if (minScale > scaleY)
+ minScale = scaleY;
+ }
+ fontEmSize *= minScale;
+ }
+
+ CustomGlyphRun(const CustomGlyphRun& other)
+ : DWRITE_GLYPH_RUN(other)
+ , sumCharWidth(other.sumCharWidth)
+ {
+ glyphAdvances = new float[other.glyphCount];
+ for (unsigned i = 0; i < other.glyphCount; ++i)
+ const_cast<float*>(glyphAdvances)[i] = other.glyphAdvances[i];
+ }
+
+ ~CustomGlyphRun()
+ {
+ delete[] glyphAdvances;
+ }
+
+ float sumCharWidth;
+};
+
+struct DrawGlyphRunParams
+{
+ DrawGlyphRunParams(
+ float fBaselineOriginXOther,
+ float fBaselineOriginYOther,
+ DWRITE_MEASURING_MODE measuringModeOther,
+ const DWRITE_GLYPH_RUN& glyphRunOther)
+ : glyphRun(glyphRunOther)
+ , fBaselineOriginX(fBaselineOriginXOther)
+ , fBaselineOriginY(fBaselineOriginYOther)
+ , measuringMode(measuringModeOther)
+ {
+ glyphRun.glyphAdvances = new FLOAT[glyphRunOther.glyphCount];
+ glyphRun.glyphIndices = new UINT16[glyphRunOther.glyphCount];
+ glyphRun.glyphOffsets = glyphRunOther.glyphOffsets ? new DWRITE_GLYPH_OFFSET[glyphRunOther.glyphCount] : nullptr;
+ glyphRun.fontFace->AddRef();
+ for (unsigned i = 0; i < glyphRunOther.glyphCount; ++i)
+ {
+ const_cast<float *>(glyphRun.glyphAdvances)[i] = glyphRunOther.glyphAdvances[i];
+ const_cast<UINT16 *>(glyphRun.glyphIndices)[i] = glyphRunOther.glyphIndices[i];
+ if (glyphRunOther.glyphOffsets)
+ const_cast<DWRITE_GLYPH_OFFSET *>(glyphRun.glyphOffsets)[i] = glyphRunOther.glyphOffsets[i];
+ }
+ }
+
+ DrawGlyphRunParams(const DrawGlyphRunParams &other)
+ : glyphRun(other.glyphRun)
+ , fBaselineOriginX(other.fBaselineOriginX)
+ , fBaselineOriginY(other.fBaselineOriginY)
+ , measuringMode(other.measuringMode)
+ {
+ glyphRun.glyphAdvances = new FLOAT[other.glyphRun.glyphCount];
+ glyphRun.glyphIndices = new UINT16[other.glyphRun.glyphCount];
+ glyphRun.glyphOffsets = other.glyphRun.glyphOffsets ? new DWRITE_GLYPH_OFFSET[other.glyphRun.glyphCount] : nullptr;
+ glyphRun.fontFace->AddRef();
+ for (unsigned i = 0; i < other.glyphRun.glyphCount; ++i)
+ {
+ const_cast<FLOAT *>(glyphRun.glyphAdvances)[i] = other.glyphRun.glyphAdvances[i];
+ const_cast<UINT16 *>(glyphRun.glyphIndices)[i] = other.glyphRun.glyphIndices[i];
+ if (other.glyphRun.glyphOffsets)
+ const_cast<DWRITE_GLYPH_OFFSET *>(glyphRun.glyphOffsets)[i] = other.glyphRun.glyphOffsets[i];
+ }
+ }
+
+ ~DrawGlyphRunParams()
+ {
+ delete glyphRun.glyphAdvances;
+ delete glyphRun.glyphIndices;
+ delete glyphRun.glyphOffsets;
+ glyphRun.fontFace->Release();
+ }
+
+ FLOAT fBaselineOriginX;
+ FLOAT fBaselineOriginY;
+ DWRITE_MEASURING_MODE measuringMode;
+ DWRITE_GLYPH_RUN glyphRun;
+};
+
+class CDrawingContext
+{
+public:
+ CDrawingContext(CRenderTarget* pRenderTarget)
+ : m_pRenderTarget(pRenderTarget)
+ {
+ }
+
+ CRenderTarget* m_pRenderTarget;
+ std::vector<DrawGlyphRunParams> m_drawGlyphRunParams;
+};
+
+class CCustomTextRenderer : public CCmdTarget
+{
+ DECLARE_DYNAMIC(CCustomTextRenderer)
+public:
+ CCustomTextRenderer() = default;
+ virtual ~CCustomTextRenderer() = default;
+ IDWriteTextRenderer* Get();
+public:
+ DECLARE_INTERFACE_MAP()
+ BEGIN_INTERFACE_PART(CustomTextRenderer, IDWriteTextRenderer)
+ // override IDWriteTextRenderer
+ STDMETHOD(DrawGlyphRun)(void*, FLOAT, FLOAT, DWRITE_MEASURING_MODE, const DWRITE_GLYPH_RUN*,
+ const DWRITE_GLYPH_RUN_DESCRIPTION*, IUnknown*);
+ STDMETHOD(DrawInlineObject)(void*, FLOAT, FLOAT, IDWriteInlineObject*, BOOL, BOOL, IUnknown*);
+ STDMETHOD(DrawStrikethrough)(void*, FLOAT, FLOAT, const DWRITE_STRIKETHROUGH*, IUnknown*);
+ STDMETHOD(DrawUnderline)(void*, FLOAT, FLOAT, const DWRITE_UNDERLINE*, IUnknown*);
+ // override IDWritePixelSnapping
+ STDMETHOD(GetCurrentTransform)(void*, DWRITE_MATRIX*);
+ STDMETHOD(GetPixelsPerDip)(void*, FLOAT*);
+ STDMETHOD(IsPixelSnappingDisabled)(void*, BOOL*);
+ // implementation helpers
+ END_INTERFACE_PART(CustomTextRenderer)
+};
+
+inline IDWriteTextRenderer* CCustomTextRenderer::Get()
+{
+ return &m_xCustomTextRenderer;
+}
+
+IMPLEMENT_DYNAMIC(CCustomTextRenderer, CCmdTarget)
+
+BEGIN_INTERFACE_MAP(CCustomTextRenderer, CCmdTarget)
+ INTERFACE_PART(CCustomTextRenderer, __uuidof(IDWriteTextRenderer), CustomTextRenderer)
+END_INTERFACE_MAP()
+
+STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::DrawGlyphRun(void* pClientDrawingContext,
+ FLOAT fBaselineOriginX, FLOAT fBaselineOriginY, DWRITE_MEASURING_MODE measuringMode,
+ const DWRITE_GLYPH_RUN* pGlyphRun, const DWRITE_GLYPH_RUN_DESCRIPTION* pGlyphRunDescription,
+ IUnknown* pClientDrawingEffect)
+{
+ CDrawingContext* pDrawingContext = static_cast<CDrawingContext*>(pClientDrawingContext);
+ pDrawingContext->m_drawGlyphRunParams.push_back(
+ DrawGlyphRunParams{fBaselineOriginX, fBaselineOriginY, measuringMode, *pGlyphRun});
+ return S_OK;
+}
+
+STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::DrawInlineObject(void* pClientDrawingContext,
+ FLOAT fOriginX, FLOAT fOriginY, IDWriteInlineObject* pInlineObject,
+ BOOL bIsSideways, BOOL bIsRightToLeft,
+ IUnknown* pClientDrawingEffect)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::DrawStrikethrough(void* pClientDrawingContext,
+ FLOAT fBaselineOriginX, FLOAT fBaselineOriginY, const DWRITE_STRIKETHROUGH* pStrikethrough,
+ IUnknown* pClientDrawingEffect)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::DrawUnderline(void* pClientDrawingContext,
+ FLOAT fBaselineOriginX, FLOAT fBaselineOriginY, const DWRITE_UNDERLINE* pUnderline,
+ IUnknown* pClientDrawingEffect)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::GetCurrentTransform(void* pClientDrawingContext, DWRITE_MATRIX* pTransform)
+{
+ CDrawingContext* pDrawingContext = static_cast<CDrawingContext*>(pClientDrawingContext);
+ pDrawingContext->m_pRenderTarget->GetTransform((D2D1_MATRIX_3X2_F*)pTransform);
+ return S_OK;
+}
+
+STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::GetPixelsPerDip(void* pClientDrawingContext, FLOAT* pfPixelsPerDip)
+{
+ CDrawingContext* pDrawingContext = static_cast<CDrawingContext*>(pClientDrawingContext);
+ *pfPixelsPerDip = pDrawingContext->m_pRenderTarget->GetDpi().width / 96.0f;
+ return S_OK;
+}
+
+STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::IsPixelSnappingDisabled(void* pClientDrawingContext, BOOL* pbIsDisabled)
+{
+ *pbIsDisabled = FALSE;
+ return S_OK;
+}
+
+STDMETHODIMP_(ULONG) CCustomTextRenderer::XCustomTextRenderer::AddRef()
+{
+ METHOD_PROLOGUE(CCustomTextRenderer, CustomTextRenderer);
+ return pThis->ExternalAddRef();
+}
+
+STDMETHODIMP_(ULONG) CCustomTextRenderer::XCustomTextRenderer::Release()
+{
+ METHOD_PROLOGUE(CCustomTextRenderer, CustomTextRenderer);
+ return pThis->ExternalRelease();
+}
+
+STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::QueryInterface(REFIID iid, LPVOID far* ppvObj)
+{
+ METHOD_PROLOGUE(CCustomTextRenderer, CustomTextRenderer);
+ return pThis->ExternalQueryInterface(&iid, ppvObj);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CCrystalRendererDirectWrite construction/destruction
+
+
+CCrystalRendererDirectWrite::CCrystalRendererDirectWrite(int nRenderingMode)
+ : m_pCurrentTextFormat{ nullptr }, m_charSize{}, m_lfBaseFont{}, m_fontAscent(0)
+ , m_pTextBrush(new CD2DSolidColorBrush(&m_renderTarget, D2D1::ColorF(D2D1::ColorF::Black)))
+ , m_pTempBrush(new CD2DSolidColorBrush(&m_renderTarget, D2D1::ColorF(D2D1::ColorF::Black)))
+ , m_pBackgroundBrush(new CD2DSolidColorBrush(&m_renderTarget, D2D1::ColorF(D2D1::ColorF::White)))
+ , m_pTextRenderer(new CCustomTextRenderer())
+{
+ const auto 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
+ );
+
+ m_renderTarget.Create(props);
+ IDWriteFactory *pWriteFactory = AfxGetD2DState()->GetWriteFactory();
+ CComPtr<IDWriteRenderingParams> pTextRenderingParams, pTextRenderingParams2;
+ pWriteFactory->CreateRenderingParams(&pTextRenderingParams);
+ pWriteFactory->CreateCustomRenderingParams(
+ pTextRenderingParams->GetGamma(),
+ pTextRenderingParams->GetEnhancedContrast(),
+ 1.0f,
+ pTextRenderingParams->GetPixelGeometry(),
+ static_cast<DWRITE_RENDERING_MODE>(nRenderingMode),
+ &pTextRenderingParams2);
+ m_renderTarget.SetTextRenderingParams(pTextRenderingParams2);
+ m_renderTarget.SetDpi(CD2DSizeF(96.0F, 96.0F));
+}
+
+CCrystalRendererDirectWrite::~CCrystalRendererDirectWrite ()
+{
+}
+
+void CCrystalRendererDirectWrite::BindDC(const CDC& dc, const CRect& rc)
+{
+ m_renderTarget.BindDC(dc, rc);
+}
+
+void CCrystalRendererDirectWrite::BeginDraw()
+{
+ m_renderTarget.BeginDraw();
+}
+
+bool CCrystalRendererDirectWrite::EndDraw()
+{
+ return (SUCCEEDED(m_renderTarget.EndDraw()));
+}
+
+static D2D1_SIZE_F GetCharWidthHeight(IDWriteTextFormat *pTextFormat)
+{
+ CComPtr<IDWriteTextLayout> pTextLayout;
+ AfxGetD2DState()->GetWriteFactory()->CreateTextLayout(L"W", 1, pTextFormat, 0, 0, &pTextLayout);
+ DWRITE_TEXT_METRICS textMetrics{};
+ pTextLayout->GetMetrics(&textMetrics);
+ return {textMetrics.width, textMetrics.height};
+}
+
+static float GetFontAscent(IDWriteTextFormat* pTextFormat)
+{
+ CComPtr<IDWriteFontCollection> pFontCollection;
+ pTextFormat->GetFontCollection(&pFontCollection);
+ if (pFontCollection)
+ {
+ CComPtr<IDWriteFontFamily> pFontFamily;
+ pFontCollection->GetFontFamily(0, &pFontFamily);
+ if (pFontFamily)
+ {
+ CComPtr<IDWriteFont> pFont;
+ pFontFamily->GetFont(0, &pFont);
+ if (pFont)
+ {
+ DWRITE_FONT_METRICS fontMetrics;
+ pFont->GetMetrics(&fontMetrics);
+ return fontMetrics.ascent * (pTextFormat->GetFontSize() / fontMetrics.designUnitsPerEm);
+ }
+ }
+ }
+ return pTextFormat->GetFontSize() * 0.7f;
+}
+
+void CCrystalRendererDirectWrite::SetFont(const LOGFONT &lf)
+{
+ m_lfBaseFont = lf;
+ for (int nIndex = 0; nIndex < 4; ++nIndex)
+ {
+ bool bold = (nIndex & 1) != 0;
+ bool italic = (nIndex & 2) != 0;
+ m_pTextFormat[nIndex].reset(new CD2DTextFormat(&m_renderTarget,
+ lf.lfFaceName[0] ? lf.lfFaceName : L"Courier New",
+ static_cast<FLOAT>(abs(lf.lfHeight == 0 ? 11 : lf.lfHeight)),
+ bold ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_NORMAL,
+ italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL));
+ IDWriteTextFormat *pTextFormat = m_pTextFormat[nIndex]->Get();
+ pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
+ pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
+ pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
+ }
+ m_pCurrentTextFormat = m_pTextFormat[0].get();
+ m_pFont.reset();
+ m_charSize = ::GetCharWidthHeight(m_pTextFormat[3]->Get());
+ m_fontAscent = ::GetFontAscent(m_pTextFormat[3]->Get());
+}
+
+void CCrystalRendererDirectWrite::SwitchFont(bool italic, bool bold)
+{
+ int nIndex = 0;
+ if (bold)
+ nIndex |= 1;
+ if (italic)
+ nIndex |= 2;
+ m_pCurrentTextFormat = m_pTextFormat[nIndex].get();
+}
+
+CSize CCrystalRendererDirectWrite::GetCharWidthHeight()
+{
+ if (m_pTextFormat[3] == nullptr)
+ SetFont(m_lfBaseFont);
+ return CSize(static_cast<int>(m_charSize.width), static_cast<int>(m_charSize.height));
+}
+
+bool CCrystalRendererDirectWrite::GetCharWidth(unsigned start, unsigned end, int * nWidthArray)
+{
+ if (!m_pFont)
+ {
+ m_pFont.reset(new CFont());
+ m_pFont->CreateFontIndirect(&m_lfBaseFont);
+ }
+ CClientDC dc (CWnd::GetDesktopWindow());
+ CFont *pOldFont = dc.SelectObject(m_pFont.get());
+ bool succeeded = !!GetCharWidth32(dc.m_hDC, start, end, nWidthArray);
+ dc.SelectObject(pOldFont);
+ return succeeded;
+}
+
+void CCrystalRendererDirectWrite::SetTextColor(COLORREF clr)
+{
+ m_pTextBrush->SetColor(ColorRefToColorF(clr));
+}
+
+void CCrystalRendererDirectWrite::SetBkColor(COLORREF clr)
+{
+ m_pBackgroundBrush->SetColor(ColorRefToColorF(clr));
+}
+
+void CCrystalRendererDirectWrite::FillRectangle(const CRect &rc)
+{
+ m_renderTarget.FillRectangle(CD2DRectF(rc), m_pBackgroundBrush.get());
+}
+
+void CCrystalRendererDirectWrite::FillSolidRectangle(const CRect &rc, COLORREF color)
+{
+ m_pTempBrush->SetColor(ColorRefToColorF(color));
+ m_renderTarget.FillRectangle(CD2DRectF(rc), m_pTempBrush.get());
+}
+
+void CCrystalRendererDirectWrite::DrawRoundRectangle(int left, int top, int right, int bottom, int width, int height)
+{
+ m_renderTarget.DrawRoundedRectangle(
+ D2D1_ROUNDED_RECT{ {static_cast<float>(left), static_cast<float>(top), static_cast<float>(right), static_cast<float>(bottom)},
+ static_cast<float>(width), static_cast<float>(height) }, m_pTextBrush.get());
+}
+
+void CCrystalRendererDirectWrite::PushAxisAlignedClip(const CRect & rc)
+{
+ m_renderTarget.PushAxisAlignedClip(rc);
+}
+
+void CCrystalRendererDirectWrite::PopAxisAlignedClip()
+{
+ m_renderTarget.PopAxisAlignedClip();
+}
+
+void CCrystalRendererDirectWrite::DrawMarginIcon(int x, int y, int iconIndex)
+{
+ if (!m_pIconBitmap)
+ {
+ m_pIconBitmap.reset(new CD2DBitmap(nullptr, static_cast<UINT>(IDR_MARGIN_ICONS_PNG), L"IMAGE"));
+ m_pIconBitmap->Create(&m_renderTarget);
+ }
+ auto size = m_pIconBitmap->GetPixelSize();
+ CD2DRectF rcSrc{static_cast<float>(iconIndex * MARGIN_ICON_WIDTH), 0.0f, static_cast<float>((iconIndex + 1) * MARGIN_ICON_WIDTH), static_cast<float>(MARGIN_ICON_HEIGHT)};
+ m_renderTarget.DrawBitmap(m_pIconBitmap.get(),
+ { static_cast<float>(x), static_cast<float>(y),
+ static_cast<float>(x + MARGIN_ICON_WIDTH), static_cast<float>(y + MARGIN_ICON_HEIGHT) },
+ 1.0f, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, &rcSrc);
+}
+
+void CCrystalRendererDirectWrite::DrawMarginLineNumber(int x, int y, int number)
+{
+ TCHAR szNumbers[32];
+ int len = wsprintf(szNumbers, _T("%d"), number);
+ m_renderTarget.DrawText(szNumbers,
+ { static_cast<float>(x) - m_charSize.width * len - 4, static_cast<float>(y),
+ static_cast<float>(x), static_cast<float>(y + m_charSize.height) },
+ m_pTextBrush.get(), m_pTextFormat[0].get());
+}
+
+void CCrystalRendererDirectWrite::DrawBoundaryLine(int left, int right, int y)
+{
+ m_pTempBrush->SetColor(ColorRefToColorF(0));
+ m_renderTarget.DrawLine(
+ { static_cast<float>(left), static_cast<float>(y) },
+ { static_cast<float>(right), static_cast<float>(y) }, m_pTempBrush.get());
+}
+
+void CCrystalRendererDirectWrite::DrawLineCursor(int left, int right, int y, int height)
+{
+ m_pTempBrush->SetColor(ColorRefToColorF(0));
+ m_pTempBrush->SetOpacity(0.5f);
+ m_renderTarget.DrawLine(
+ { static_cast<float>(left), static_cast<float>(y) },
+ { static_cast<float>(right), static_cast<float>(y) },
+ m_pTempBrush.get(), static_cast<float>(1));
+ m_pTempBrush->SetOpacity(1.0f);
+}
+
+void CCrystalRendererDirectWrite::DrawText(int x, int y, const CRect &rc, const TCHAR *text, size_t len, const int nWidths[])
+{
+ CD2DRectF rcF(rc);
+
+ m_renderTarget.PushAxisAlignedClip(rcF);
+
+ m_renderTarget.FillRectangle(rcF, m_pBackgroundBrush.get());
+
+ D2D1_COLOR_F textColor = m_pTextBrush->GetColor();
+ D2D1_COLOR_F backColor = m_pBackgroundBrush->GetColor();
+ if (memcmp(&textColor, &backColor, sizeof(D2D1_COLOR_F)) != 0)
+ {
+ CDrawingContext drawingContext{ &m_renderTarget };
+ CComPtr<IDWriteTextLayout> pTextLayout;
+ AfxGetD2DState()->GetWriteFactory()->CreateTextLayout(text, static_cast<unsigned>(len),
+ *m_pCurrentTextFormat,
+ rcF.right - rcF.left, rcF.bottom - rcF.top, &pTextLayout);
+ pTextLayout->Draw(&drawingContext, m_pTextRenderer->Get(), 0, 0);
+
+ std::vector<std::pair<size_t, float>> orders;
+ for (size_t i = 0; i < drawingContext.m_drawGlyphRunParams.size(); ++i)
+ orders.emplace_back(i, drawingContext.m_drawGlyphRunParams[i].fBaselineOriginX);
+ std::stable_sort(orders.begin(), orders.end(),
+ [](const std::pair<size_t, float>& a, const std::pair<size_t, float>& b)
+ { return a.second < b.second; });
+ float fBaselineOriginX = static_cast<float>(x);
+ float fBaselineOriginY = y + m_fontAscent;
+ for (size_t i = 0; i < orders.size(); ++i)
+ {
+ DrawGlyphRunParams& param = drawingContext.m_drawGlyphRunParams[orders[i].first];
+ CustomGlyphRun customGlyphRun2(param.glyphRun, m_charSize.width, m_charSize.height);
+ DrawGlyphRun(&drawingContext,
+ (customGlyphRun2.bidiLevel & 1) ? (fBaselineOriginX + customGlyphRun2.sumCharWidth) : fBaselineOriginX,
+ fBaselineOriginY,
+ param.measuringMode, &customGlyphRun2, nullptr, nullptr);
+ fBaselineOriginX += customGlyphRun2.sumCharWidth;
+ }
+ }
+ m_renderTarget.PopAxisAlignedClip();
+}
+
+STDMETHODIMP CCrystalRendererDirectWrite::DrawGlyphRun(void* pClientDrawingContext,
+ FLOAT fBaselineOriginX, FLOAT fBaselineOriginY, DWRITE_MEASURING_MODE measuringMode,
+ const DWRITE_GLYPH_RUN* pGlyphRun, const DWRITE_GLYPH_RUN_DESCRIPTION* pGlyphRunDescription,
+ IUnknown* pClientDrawingEffect)
+{
+ IDWriteFactory *pWriteFactory = AfxGetD2DState()->GetWriteFactory();
+ CComQIPtr<IDWriteFactory4> pWriteFactory4(pWriteFactory);
+ CComQIPtr<ID2D1DeviceContext4> pD2dDeviceContext(m_renderTarget);
+ CComPtr<IDWriteColorGlyphRunEnumerator1> glyphRunEnumerator;
+
+ DWRITE_GLYPH_IMAGE_FORMATS supportedFormats = static_cast<DWRITE_GLYPH_IMAGE_FORMATS>(
+ static_cast<int>(DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE) |
+ static_cast<int>(DWRITE_GLYPH_IMAGE_FORMATS_CFF) |
+ static_cast<int>(DWRITE_GLYPH_IMAGE_FORMATS_COLR) |
+ static_cast<int>(DWRITE_GLYPH_IMAGE_FORMATS_SVG) |
+ static_cast<int>(DWRITE_GLYPH_IMAGE_FORMATS_PNG) |
+ static_cast<int>(DWRITE_GLYPH_IMAGE_FORMATS_JPEG)|
+ static_cast<int>(DWRITE_GLYPH_IMAGE_FORMATS_TIFF) |
+ static_cast<int>(DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8)
+ );
+
+ if (!pWriteFactory4)
+ {
+ m_renderTarget.DrawGlyphRun(
+ {fBaselineOriginX, fBaselineOriginY},
+ *pGlyphRun, m_pTextBrush.get(), measuringMode);
+ return S_OK;
+ }
+
+ HRESULT hr = pWriteFactory4->TranslateColorGlyphRun(
+ {fBaselineOriginX, fBaselineOriginY},
+ pGlyphRun, pGlyphRunDescription, supportedFormats,
+ measuringMode, nullptr, 0, &glyphRunEnumerator);
+ if (hr == DWRITE_E_NOCOLOR)
+ {
+ m_renderTarget.DrawGlyphRun(
+ {fBaselineOriginX, fBaselineOriginY},
+ *pGlyphRun, m_pTextBrush.get(), measuringMode);
+ return S_OK;
+ }
+
+ for (;;)
+ {
+ BOOL haveRun;
+ glyphRunEnumerator->MoveNext(&haveRun);
+ if (!haveRun)
+ break;
+
+ DWRITE_COLOR_GLYPH_RUN1 const* colorRun;
+ glyphRunEnumerator->GetCurrentRun(&colorRun);
+
+ D2D1_POINT_2F currentBaselineOrigin = D2D1::Point2F(
+ colorRun->baselineOriginX,
+ colorRun->baselineOriginY
+ );
+
+ switch (colorRun->glyphImageFormat)
+ {
+ case DWRITE_GLYPH_IMAGE_FORMATS_PNG:
+ case DWRITE_GLYPH_IMAGE_FORMATS_JPEG:
+ case DWRITE_GLYPH_IMAGE_FORMATS_TIFF:
+ case DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8:
+ {
+ // This run is bitmap glyphs. Use Direct2D to draw them.
+ pD2dDeviceContext->DrawColorBitmapGlyphRun(
+ colorRun->glyphImageFormat, currentBaselineOrigin,
+ &colorRun->glyphRun, measuringMode);
+ }
+ break;
+
+ case DWRITE_GLYPH_IMAGE_FORMATS_SVG:
+ {
+ // This run is SVG glyphs. Use Direct2D to draw them.
+ pD2dDeviceContext->DrawSvgGlyphRun(
+ currentBaselineOrigin, &colorRun->glyphRun,
+ m_pTextBrush->Get(),
+ nullptr, 0, measuringMode);
+ }
+ break;
+
+ case DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE:
+ case DWRITE_GLYPH_IMAGE_FORMATS_CFF:
+ case DWRITE_GLYPH_IMAGE_FORMATS_COLR:
+ default:
+ {
+ // This run is solid-color outlines, either from non-color
+ // glyphs or from COLR glyph layers. Use Direct2D to draw them.
+
+ ID2D1Brush* layerBrush;
+ if (colorRun->paletteIndex == 0xFFFF)
+ {
+ // This run uses the current text color.
+ layerBrush = m_pTextBrush->Get();
+ }
+ else
+ {
+ // This run specifies its own color.
+ m_pTempBrush->SetColor(colorRun->runColor);
+ layerBrush = m_pTempBrush->Get();
+ }
+
+ // Draw the run with the selected color.
+ pD2dDeviceContext->DrawGlyphRun(currentBaselineOrigin, &colorRun->glyphRun,
+ colorRun->glyphRunDescription, layerBrush, measuringMode);
+ }
+ break;
+ }
+ }
+ return S_OK;
+}
+
+#endif
--- /dev/null
+/**
+ * @file ccrystalrendererdirectdraw.h
+ *
+ * @brief Declaration file for CCrystalRendererDirectWrite
+ */
+#include "ccrystalrenderer.h"
+#include <memory>
+#include <array>
+#include <afxwin.h>
+
+#pragma once
+
+////////////////////////////////////////////////////////////////////////////
+// Forward class declarations
+class CCustomTextRenderer;
+
+////////////////////////////////////////////////////////////////////////////
+// CCrystalRendererDirectWrite class declaration
+
+class CCrystalRendererDirectWrite : public CCrystalRenderer
+{
+public:
+ CCrystalRendererDirectWrite(int nRenderingMode = 1);
+ virtual ~CCrystalRendererDirectWrite();
+
+ virtual void BindDC(const CDC& dc, const CRect& rc);
+ virtual void BeginDraw();
+ virtual bool EndDraw();
+ virtual void SetFont(const LOGFONT &lf);
+ virtual void SwitchFont(bool italic, bool bold);
+ virtual CSize GetCharWidthHeight();
+ virtual bool GetCharWidth(unsigned start, unsigned end, int *nWidthArray);
+ virtual void SetTextColor(COLORREF clr);
+ virtual void SetBkColor(COLORREF clr);
+ virtual void DrawText(int x, int y, const CRect &rc, const TCHAR *text, size_t len, const int nWidths[]);
+ virtual void FillRectangle(const CRect &rc);
+ virtual void FillSolidRectangle(const CRect &rc, COLORREF color);
+ virtual void DrawRoundRectangle(int left, int top , int right, int bottom, int width, int height);
+ virtual void PushAxisAlignedClip(const CRect &rc);
+ virtual void PopAxisAlignedClip();
+ virtual void DrawMarginIcon(int x, int y, int iconIndex);
+ virtual void DrawMarginLineNumber(int x, int y, int number);
+ virtual void DrawBoundaryLine(int left, int right, int y);
+ virtual void DrawLineCursor(int left, int right, int y, int height);
+
+private:
+ STDMETHODIMP DrawGlyphRun(void* pClientDrawingContext,
+ FLOAT fBaselineOriginX, FLOAT fBaselineOriginY, DWRITE_MEASURING_MODE measuringMode,
+ const DWRITE_GLYPH_RUN* pGlyphRun, const DWRITE_GLYPH_RUN_DESCRIPTION* pGlyphRunDescription,
+ IUnknown* pClientDrawingEffect);
+
+ D2D1::ColorF ColorRefToColorF(COLORREF cr) const
+ {
+ return D2D1::ColorF(GetRValue(cr) / 255.0f, GetGValue(cr) / 255.0f, GetBValue(cr) / 255.0f);
+ };
+
+ CDCRenderTarget m_renderTarget;
+ std::array<std::unique_ptr<CD2DTextFormat>, 4> m_pTextFormat;
+ CD2DTextFormat *m_pCurrentTextFormat;
+ std::unique_ptr<CD2DSolidColorBrush> m_pTextBrush;
+ std::unique_ptr<CD2DSolidColorBrush> m_pTempBrush;
+ std::unique_ptr<CD2DSolidColorBrush> m_pBackgroundBrush;
+ std::unique_ptr<CCustomTextRenderer> m_pTextRenderer;
+ std::unique_ptr<CD2DBitmap> m_pIconBitmap;
+ LOGFONT m_lfBaseFont;
+ std::unique_ptr<CFont> m_pFont;
+ D2D1_SIZE_F m_charSize;
+ float m_fontAscent;
+};
--- /dev/null
+/**
+ * @file ccrystalrenderergdi.cpp
+ *
+ * @brief Implementation of the CCrystalRendererGDI class
+ */
+
+#include "StdAfx.h"
+#include "ccrystalrenderergdi.h"
+
+CImageList* CCrystalRendererGDI::s_pIcons = nullptr;
+
+/////////////////////////////////////////////////////////////////////////////
+// CCrystalRendererGDI construction/destruction
+
+CCrystalRendererGDI::CCrystalRendererGDI() : m_pDC(nullptr), m_lfBaseFont{}
+{
+}
+
+CCrystalRendererGDI::~CCrystalRendererGDI ()
+{
+}
+
+void CCrystalRendererGDI::BindDC(const CDC& dc, const CRect& rc)
+{
+ m_pDC = const_cast<CDC *>(&dc);
+}
+
+void CCrystalRendererGDI::BeginDraw()
+{
+}
+
+bool CCrystalRendererGDI::EndDraw()
+{
+ return true;
+}
+
+void CCrystalRendererGDI::SetFont(const LOGFONT &lf)
+{
+ m_lfBaseFont = lf;
+ for (int nIndex = 0; nIndex < 4; ++nIndex)
+ {
+ bool bold = (nIndex & 1) != 0;
+ bool italic = (nIndex & 2) != 0;
+ m_apFonts[nIndex].reset(new CFont());
+ if (!m_lfBaseFont.lfHeight)
+ {
+ CClientDC dc (CWnd::GetDesktopWindow());
+ m_lfBaseFont.lfHeight = -MulDiv (11, dc.GetDeviceCaps (LOGPIXELSY), 72);
+ }
+ m_lfBaseFont.lfWeight = bold ? FW_BOLD : FW_NORMAL;
+ m_lfBaseFont.lfItalic = (BYTE) italic;
+ if (!m_apFonts[nIndex]->CreateFontIndirect(&m_lfBaseFont))
+ m_apFonts[nIndex].reset(nullptr);
+ }
+}
+
+void CCrystalRendererGDI::SwitchFont(bool italic, bool bold)
+{
+ int nIndex = 0;
+ if (bold)
+ nIndex |= 1;
+ if (italic)
+ nIndex |= 2;
+ m_pDC->SelectObject(m_apFonts[nIndex].get());
+}
+
+CSize CCrystalRendererGDI::GetCharWidthHeight()
+{
+ if (!m_apFonts[3])
+ SetFont(m_lfBaseFont);
+ CClientDC dc (CWnd::GetDesktopWindow());
+ CFont *pOldFont = dc.SelectObject(m_apFonts[3].get());
+ CSize sizeItalicBold = dc.GetTextExtent(_T("X"));
+ dc.SelectObject(m_apFonts[0].get());
+ CSize sizeNormal = dc.GetTextExtent(_T("X"));
+ dc.SelectObject(pOldFont);
+ return CSize{ (std::max)(sizeNormal.cx, sizeItalicBold.cx), (std::max)(sizeNormal.cy, sizeItalicBold.cy)};
+}
+
+bool CCrystalRendererGDI::GetCharWidth(unsigned start, unsigned end, int * nWidthArray)
+{
+ if (!m_apFonts[3])
+ SetFont(m_lfBaseFont);
+ CClientDC dc (CWnd::GetDesktopWindow());
+ CFont *pOldFont = dc.SelectObject(m_apFonts[3].get());
+ bool succeeded = !!GetCharWidth32(dc.m_hDC, start, end, nWidthArray);
+ dc.SelectObject(pOldFont);
+ return succeeded;
+}
+
+void CCrystalRendererGDI::SetTextColor(COLORREF clr)
+{
+ m_pDC->SetTextColor(clr);
+}
+
+void CCrystalRendererGDI::SetBkColor(COLORREF clr)
+{
+ m_pDC->SetBkColor(clr);
+}
+
+void CCrystalRendererGDI::FillRectangle(const CRect &rc)
+{
+ m_pDC->FillSolidRect(&rc, m_pDC->GetBkColor());
+}
+
+void CCrystalRendererGDI::FillSolidRectangle(const CRect &rc, COLORREF color)
+{
+ m_pDC->FillSolidRect(&rc, color);
+}
+
+void CCrystalRendererGDI::DrawRoundRectangle(int left, int top, int right, int bottom, int width, int height)
+{
+ HGDIOBJ hBrush = ::GetStockObject(NULL_BRUSH);
+ hBrush = ::SelectObject(m_pDC->m_hDC, hBrush);
+ HGDIOBJ hPen = ::CreatePen(PS_SOLID, 1, ::GetTextColor(m_pDC->m_hDC));
+ hPen = ::SelectObject(m_pDC->m_hDC, hPen);
+
+ m_pDC->RoundRect(left, top, right, bottom, width, height);
+
+ hPen = ::SelectObject(m_pDC->m_hDC, hPen);
+ ::DeleteObject(hPen);
+ hBrush = ::SelectObject(m_pDC->m_hDC, hBrush);
+}
+
+void CCrystalRendererGDI::PushAxisAlignedClip(const CRect & rc)
+{
+ m_pDC->SaveDC();
+ m_pDC->IntersectClipRect(&rc);
+}
+
+void CCrystalRendererGDI::PopAxisAlignedClip()
+{
+ m_pDC->RestoreDC(-1);
+}
+
+void CCrystalRendererGDI::DrawMarginIcon(int x, int y, int iconIndex)
+{
+ if (s_pIcons == nullptr)
+ {
+ s_pIcons = new CImageList;
+ VERIFY(s_pIcons->Create(MARGIN_ICON_WIDTH, MARGIN_ICON_HEIGHT,
+ ILC_COLOR32 | ILC_MASK, 0, 1));
+ CBitmap bmp;
+ bmp.LoadBitmap(IDR_MARGIN_ICONS);
+ s_pIcons->Add(&bmp, RGB(255, 255, 255));
+ }
+ if (iconIndex >= 0)
+ {
+ CPoint pt(x, y);
+ VERIFY(s_pIcons->Draw(m_pDC, iconIndex, pt, ILD_TRANSPARENT));
+ }
+}
+
+void CCrystalRendererGDI::DrawMarginLineNumber(int x, int y, int number)
+{
+ CFont *pOldFont = m_pDC->SelectObject(m_apFonts[0].get());
+ TCHAR szNumbers[32];
+ int len = wsprintf(szNumbers, _T("%d"), number);
+ UINT uiOldAlign = m_pDC->SetTextAlign(TA_RIGHT);
+ m_pDC->TextOut(x - (m_pDC->IsPrinting() ? 0 : 4), y, szNumbers, len);
+ m_pDC->SetTextAlign(uiOldAlign);
+ m_pDC->SelectObject(pOldFont);
+}
+
+void CCrystalRendererGDI::DrawBoundaryLine(int left, int right, int y)
+{
+ CPen *pOldPen = (CPen *)m_pDC->SelectStockObject(BLACK_PEN);
+ m_pDC->MoveTo(left, y);
+ m_pDC->LineTo(right, y);
+ m_pDC->SelectObject(pOldPen);
+}
+
+void CCrystalRendererGDI::DrawLineCursor(int left, int right, int y, int height)
+{
+ CDC dcMem;
+ dcMem.CreateCompatibleDC(m_pDC);
+ CBitmap bitmap;
+ bitmap.CreateCompatibleBitmap(m_pDC, right - left, height);
+ CBitmap *pOldBitmap = dcMem.SelectObject(&bitmap);
+ dcMem.SetBkColor(RGB(0, 255, 0));
+ BLENDFUNCTION blend = { 0 };
+ blend.BlendOp = AC_SRC_OVER;
+ blend.SourceConstantAlpha = 24;
+ m_pDC->AlphaBlend(left, y, right - left, height, &dcMem, 0, 0, right - left, height, blend);
+ dcMem.SelectObject(pOldBitmap);
+}
+
+void CCrystalRendererGDI::DrawText(int x, int y, const CRect &rc, const TCHAR *text, size_t len, const int nWidths[])
+{
+ m_pDC->ExtTextOut(x, y, ETO_CLIPPED | ETO_OPAQUE, &rc, text, static_cast<UINT>(len), const_cast<int *>(nWidths));
+}
+
--- /dev/null
+/**
+ * @file ccrystalrenderergdi.h
+ *
+ * @brief Declaration file for CCrystalRendererGDI
+ */
+#include "ccrystalrenderer.h"
+#include <memory>
+
+#pragma once
+
+////////////////////////////////////////////////////////////////////////////
+// Forward class declarations
+
+
+////////////////////////////////////////////////////////////////////////////
+// CCrystalRendererGDI class declaration
+
+
+class CCrystalRendererGDI : public CCrystalRenderer
+{
+public:
+ CCrystalRendererGDI();
+ virtual ~CCrystalRendererGDI();
+
+ virtual void BindDC(const CDC& dc, const CRect& rc);
+ virtual void BeginDraw();
+ virtual bool EndDraw();
+ virtual void SetFont(const LOGFONT &lf);
+ virtual void SwitchFont(bool italic, bool bold);
+ virtual CSize GetCharWidthHeight();
+ virtual bool GetCharWidth(unsigned start, unsigned end, int *nWidthArray);
+ virtual void SetTextColor(COLORREF clr);
+ virtual void SetBkColor(COLORREF clr);
+ virtual void DrawText(int x, int y, const CRect &rc, const TCHAR *text, size_t len, const int nWidths[]);
+ virtual void FillRectangle(const CRect &rc);
+ virtual void FillSolidRectangle(const CRect &rc, COLORREF color);
+ virtual void DrawRoundRectangle(int left, int top , int right, int bottom, int width, int height);
+ virtual void PushAxisAlignedClip(const CRect &rc);
+ virtual void PopAxisAlignedClip();
+ virtual void DrawMarginIcon(int x, int y, int iconIndex);
+ virtual void DrawMarginLineNumber(int x, int y, int number);
+ virtual void DrawBoundaryLine(int left, int right, int y);
+ virtual void DrawLineCursor(int left, int right, int y, int height);
+
+private:
+ CDC *m_pDC;
+ LOGFONT m_lfBaseFont;
+ std::array<std::unique_ptr<CFont>, 4> m_apFonts;
+ static CImageList *s_pIcons;
+};
#include "string_util.h"
#include "wcwidth.h"
#include "icu.hpp"
+#include "ccrystalrendererdirectwrite.h"
+#include "ccrystalrenderergdi.h"
using std::vector;
using CrystalLineParser::TEXTBLOCK;
IMPLEMENT_DYNCREATE (CCrystalTextView, CView)
HINSTANCE CCrystalTextView::s_hResourceInst = nullptr;
+CCrystalTextView::RENDERING_MODE CCrystalTextView::s_nRenderingModeDefault = RENDERING_MODE_GDI;
static ptrdiff_t FindStringHelper(LPCTSTR pszLineBegin, LPCTSTR pszFindWhere, LPCTSTR pszFindWhat, DWORD dwFlags, int &nLen, RxNode *&rxnode, RxMatchRes *rxmatch);
, m_bRememberLastPos(false)
, m_pColors(nullptr)
, m_nLastLineIndexCalculatedSubLineIndex(-1)
-, m_pIcons(nullptr)
-, m_apFonts{}
, m_hAccel(nullptr)
, m_pTextBuffer(nullptr)
, m_pCacheBitmap(nullptr)
, m_bIncrementalSearchBackward(false)
, m_bIncrementalFound(false)
, m_rxmatch{}
+, m_nRenderingMode(s_nRenderingModeDefault)
{
+#ifdef _WIN64
+ if (m_nRenderingMode == RENDERING_MODE_GDI)
+ m_pCrystalRenderer.reset(new CCrystalRendererGDI());
+ else
+ m_pCrystalRenderer.reset(new CCrystalRendererDirectWrite(m_nRenderingMode));
+#else
+ m_pCrystalRenderer.reset(new CCrystalRendererGDI());
+#endif
+
m_panSubLines->SetSize( 0, 4096 );
m_panSubLineIndexCache->SetSize( 0, 4096 );
ASSERT(m_pnActualLineLength != nullptr);
delete m_pnActualLineLength;
m_pnActualLineLength = nullptr;
- delete m_pIcons;
if (m_pMarkers != nullptr)
m_pMarkers->DeleteView(this);
}
* @note In ANSI build, this routine is buggy for multibytes or double-width characters
*/
void CCrystalTextView::
-DrawLineHelperImpl (CDC * pdc, CPoint & ptOrigin, const CRect & rcClip,
- int nColorIndex, int nBgColorIndex, COLORREF crText, COLORREF crBkgnd, LPCTSTR pszChars, int nOffset, int nCount, int &nActualOffset)
+DrawLineHelperImpl (CPoint & ptOrigin, const CRect & rcClip,
+ int nColorIndex,
+ int nBgColorIndex, COLORREF crText, COLORREF crBkgnd, LPCTSTR pszChars, int nOffset, int nCount, int &nActualOffset)
{
ASSERT (nCount >= 0);
if (nCount > 0)
if (ptOrigin.x + nSumWidth > rcClip.left)
{
if (crText == CLR_NONE || nColorIndex & COLORINDEX_APPLYFORCE)
- pdc->SetTextColor(GetColor(nColorIndex));
+ m_pCrystalRenderer->SetTextColor(GetColor(nColorIndex));
else
- pdc->SetTextColor(crText);
+ m_pCrystalRenderer->SetTextColor(crText);
if (crBkgnd == CLR_NONE || nBgColorIndex & COLORINDEX_APPLYFORCE)
- pdc->SetBkColor(GetColor(nBgColorIndex));
+ m_pCrystalRenderer->SetBkColor(GetColor(nBgColorIndex));
else
- pdc->SetBkColor(crBkgnd);
+ m_pCrystalRenderer->SetBkColor(crBkgnd);
- pdc->SelectObject(GetFont(GetItalic(nColorIndex),
- GetBold(nColorIndex)));
+ m_pCrystalRenderer->SwitchFont(GetItalic(nColorIndex), GetBold(nColorIndex));
// we are sure to have less than 4095 characters because all the chars are visible
RECT rcIntersect;
RECT rcTextBlock = {ptOrigin.x, ptOrigin.y, ptOrigin.x + nSumWidth + 2, ptOrigin.y + nLineHeight};
IntersectRect(&rcIntersect, &rcClip, &rcTextBlock);
- VERIFY(pdc->ExtTextOut(ptOrigin.x, ptOrigin.y, ETO_CLIPPED | ETO_OPAQUE,
- &rcIntersect, LPCTSTR(line) + ibegin, nCount1, &nWidths[0]));
+ m_pCrystalRenderer->DrawText(ptOrigin.x, ptOrigin.y, rcIntersect, LPCTSTR(line) + ibegin, nCount1, &nWidths[0]);
if (bdisphex)
{
// Draw rounded rectangles around control characters
- pdc->SaveDC();
- pdc->IntersectClipRect(&rcClip);
- HDC hDC = pdc->m_hDC;
- HGDIOBJ hBrush = ::GetStockObject(NULL_BRUSH);
- hBrush = ::SelectObject(hDC, hBrush);
- HGDIOBJ hPen = ::CreatePen(PS_SOLID, 1, ::GetTextColor(hDC));
- hPen = ::SelectObject(hDC, hPen);
+ m_pCrystalRenderer->PushAxisAlignedClip(rcClip);
int x = ptOrigin.x;
for (int j = 0 ; j < nCount1 ; ++j)
{
// Assume narrowed space is converted escape sequence leadin.
if (line[ibegin + j] == ' ' && nWidths[j] < nCharWidth)
{
- ::RoundRect(hDC, x + 2, ptOrigin.y + 1,
+ m_pCrystalRenderer->DrawRoundRectangle(x + 2, ptOrigin.y + 1,
x + 3 * nCharWidth - 2, ptOrigin.y + nLineHeight - 1,
nCharWidth / 2, nLineHeight / 2);
}
x += nWidths[j];
}
- hPen = ::SelectObject(hDC, hPen);
- ::DeleteObject(hPen);
- hBrush = ::SelectObject(hDC, hBrush);
- pdc->RestoreDC(-1);
+ m_pCrystalRenderer->PopAxisAlignedClip();
}
}
}
void CCrystalTextView::
-DrawLineHelper (CDC * pdc, CPoint & ptOrigin, const CRect & rcClip, int nColorIndex, int nBgColorIndex,
+DrawLineHelper (CPoint & ptOrigin, const CRect & rcClip, int nColorIndex, int nBgColorIndex,
COLORREF crText, COLORREF crBkgnd, LPCTSTR pszChars, int nOffset, int nCount, int &nActualOffset, CPoint ptTextPos)
{
if (nCount > 0)
// Draw part of the text before selection
if (nSelBegin > 0)
{
- DrawLineHelperImpl (pdc, ptOrigin, rcClip, nColorIndex, nBgColorIndex, crText, crBkgnd, pszChars, nOffset, nSelBegin, nActualOffset);
+ DrawLineHelperImpl (ptOrigin, rcClip, nColorIndex, nBgColorIndex, crText, crBkgnd, pszChars, nOffset, nSelBegin, nActualOffset);
}
if (nSelBegin < nSelEnd)
{
- DrawLineHelperImpl (pdc, ptOrigin, rcClip,
- nColorIndex & ~COLORINDEX_APPLYFORCE, nBgColorIndex & ~COLORINDEX_APPLYFORCE,
- GetColor (COLORINDEX_SELTEXT),
+ DrawLineHelperImpl (ptOrigin, rcClip,
+ nColorIndex & ~COLORINDEX_APPLYFORCE,
+ nBgColorIndex & ~COLORINDEX_APPLYFORCE,
+ GetColor (COLORINDEX_SELTEXT),
+
GetColor (COLORINDEX_SELBKGND),
- pszChars, nOffset + nSelBegin, nSelEnd - nSelBegin, nActualOffset);
+
+ pszChars,
+ nOffset + nSelBegin, nSelEnd - nSelBegin, nActualOffset);
}
if (nSelEnd < nCount)
{
- DrawLineHelperImpl (pdc, ptOrigin, rcClip, nColorIndex, nBgColorIndex, crText, crBkgnd, pszChars, nOffset + nSelEnd, nCount - nSelEnd, nActualOffset);
+ DrawLineHelperImpl (ptOrigin, rcClip, nColorIndex, nBgColorIndex, crText, crBkgnd, pszChars, nOffset + nSelEnd, nCount - nSelEnd, nActualOffset);
}
}
else
{
- DrawLineHelperImpl (pdc, ptOrigin, rcClip, nColorIndex, nBgColorIndex, crText, crBkgnd, pszChars, nOffset, nCount, nActualOffset);
+ DrawLineHelperImpl (ptOrigin, rcClip, nColorIndex, nBgColorIndex, crText, crBkgnd, pszChars, nOffset, nCount, nActualOffset);
}
}
}
}
}
-void CCrystalTextView::DrawScreenLine( CDC *pdc, CPoint &ptOrigin, const CRect &rcClip,
+void CCrystalTextView::DrawScreenLine( CPoint &ptOrigin, const CRect &rcClip,
const std::vector<TEXTBLOCK>& blocks, int &nActualItem,
COLORREF crText, COLORREF crBkgnd, bool bDrawWhitespace,
LPCTSTR pszChars, int nOffset, int nCount, int &nActualOffset, CPoint ptTextPos )
if (blocks[I + 1].m_nCharPos - nOffsetToUse > 0)
{
int nOldActualOffset = nActualOffset;
- DrawLineHelper(pdc, ptOrigin, rcClip, blk.m_nColorIndex, blk.m_nBgColorIndex, crText, crBkgnd, pszChars,
+ DrawLineHelper(ptOrigin, rcClip, blk.m_nColorIndex, blk.m_nBgColorIndex, crText, crBkgnd, pszChars,
(nOffset > blk.m_nCharPos)? nOffset : blk.m_nCharPos,
blocks[I + 1].m_nCharPos - nOffsetToUse,
nActualOffset, CPoint( nOffsetToUse, ptTextPos.y ));
if (bPrevZeroWidthBlock)
{
CRect rcClipZeroWidthBlock(ptOriginZeroWidthBlock.x, rcClip.top, ptOriginZeroWidthBlock.x + ZEROWIDTHBLOCK_WIDTH, rcClip.bottom);
- DrawLineHelper(pdc, ptOriginZeroWidthBlock, rcClipZeroWidthBlock, blk.m_nColorIndex, nBgColorIndexZeorWidthBlock, crText, crBkgnd, pszChars,
+ DrawLineHelper(ptOriginZeroWidthBlock, rcClipZeroWidthBlock, blk.m_nColorIndex, nBgColorIndexZeorWidthBlock, crText, crBkgnd, pszChars,
(nOffset > blk.m_nCharPos)? nOffset : blk.m_nCharPos,
blocks[I + 1].m_nCharPos - nOffsetToUse,
nOldActualOffset, CPoint( nOffsetToUse, ptTextPos.y ));
clrBkColor = GetColor(nBgColorIndex);
else
clrBkColor = crBkgnd;
- pdc->FillSolidRect(ptOrigin.x, ptOrigin.y, ZEROWIDTHBLOCK_WIDTH, GetLineHeight(), clrBkColor);
+ CRect rc(ptOrigin.x, ptOrigin.y, ptOrigin.x + ZEROWIDTHBLOCK_WIDTH, ptOrigin.y + GetLineHeight());
+ m_pCrystalRenderer->SetBkColor(clrBkColor);
+ m_pCrystalRenderer->FillRectangle(rc);
ptOriginZeroWidthBlock = ptOrigin;
nBgColorIndexZeorWidthBlock = blk.m_nBgColorIndex;
bPrevZeroWidthBlock = true;
if (nOffset + nCount - blocks[nActualItem].m_nCharPos > 0)
{
int nOldActualOffset = nActualOffset;
- DrawLineHelper(pdc, ptOrigin, rcClip, blocks[nActualItem].m_nColorIndex, blocks[nActualItem].m_nBgColorIndex,
+ DrawLineHelper(ptOrigin, rcClip, blocks[nActualItem].m_nColorIndex, blocks[nActualItem].m_nBgColorIndex,
crText, crBkgnd, pszChars, blocks[nActualItem].m_nCharPos,
nOffset + nCount - blocks[nActualItem].m_nCharPos,
nActualOffset, CPoint(blocks[nActualItem].m_nCharPos, ptTextPos.y));
if (bPrevZeroWidthBlock)
{
CRect rcClipZeroWidthBlock(ptOriginZeroWidthBlock.x, rcClip.top, ptOriginZeroWidthBlock.x + ZEROWIDTHBLOCK_WIDTH, rcClip.bottom);
- DrawLineHelper(pdc, ptOriginZeroWidthBlock, rcClipZeroWidthBlock, blocks[nActualItem].m_nColorIndex, nBgColorIndexZeorWidthBlock,
+ DrawLineHelper(ptOriginZeroWidthBlock, rcClipZeroWidthBlock, blocks[nActualItem].m_nColorIndex, nBgColorIndexZeorWidthBlock,
crText, crBkgnd, pszChars, blocks[nActualItem].m_nCharPos,
nOffset + nCount - blocks[nActualItem].m_nCharPos,
nOldActualOffset, CPoint(blocks[nActualItem].m_nCharPos, ptTextPos.y));
clrBkColor = GetColor(nBgColorIndex);
else
clrBkColor = crBkgnd;
- pdc->FillSolidRect(ptOrigin.x, ptOrigin.y, ZEROWIDTHBLOCK_WIDTH, GetLineHeight(), clrBkColor);
+ CRect rc(ptOrigin.x, ptOrigin.y, ptOrigin.x + ZEROWIDTHBLOCK_WIDTH, ptOrigin.y + GetLineHeight());
+ m_pCrystalRenderer->SetBkColor(clrBkColor);
+ m_pCrystalRenderer->FillRectangle(rc);
bPrevZeroWidthBlock = true;
}
}
else
{
DrawLineHelper(
- pdc, ptOrigin, rcClip, blocks[nActualItem].m_nColorIndex, blocks[nActualItem].m_nBgColorIndex,
+ ptOrigin, rcClip, blocks[nActualItem].m_nColorIndex, blocks[nActualItem].m_nBgColorIndex,
crText, crBkgnd, pszChars, nOffset, nCount, nActualOffset, ptTextPos);
}
if (frect.left >= rcClip.left)
{
const int nCharWidth = GetCharWidth();
- pdc->FillSolidRect(frect.left, frect.top, nCharWidth, frect.Height(),
- GetColor(COLORINDEX_SELBKGND));
+ CRect rc(frect.left, frect.top, frect.left + nCharWidth, frect.bottom);
+ m_pCrystalRenderer->SetBkColor(GetColor(COLORINDEX_SELBKGND));
+ m_pCrystalRenderer->FillRectangle(rc);
frect.left += nCharWidth;
}
}
frect.left = rcClip.left;
if (frect.right > frect.left)
- pdc->FillSolidRect(frect, bDrawWhitespace ?
- crBkgnd : GetColor(COLORINDEX_WHITESPACE));
+ {
+ m_pCrystalRenderer->SetBkColor(bDrawWhitespace ? crBkgnd : GetColor(COLORINDEX_WHITESPACE));
+ m_pCrystalRenderer->FillRectangle(frect);
+ }
// set origin to beginning of next screen line
ptOrigin.x = originalOrigin.x;
}
void CCrystalTextView::
-DrawSingleLine (CDC * pdc, const CRect & rc, int nLineIndex)
+DrawSingleLine (const CRect & rc, int nLineIndex)
{
const int nCharWidth = GetCharWidth();
ASSERT (nLineIndex >= -1 && nLineIndex < GetLineCount ());
if (nLineIndex == -1)
{
// Draw line beyond the text
- pdc->FillSolidRect (rc, GetColor (COLORINDEX_WHITESPACE));
+ m_pCrystalRenderer->FillSolidRectangle (rc, GetColor (COLORINDEX_WHITESPACE));
return;
}
// Draw the line text
CPoint origin (rc.left - m_nOffsetChar * nCharWidth, rc.top);
if (crBkgnd != CLR_NONE)
- pdc->SetBkColor (crBkgnd);
+ m_pCrystalRenderer->SetBkColor (crBkgnd);
if (crText != CLR_NONE)
- pdc->SetTextColor (crText);
+ m_pCrystalRenderer->SetTextColor (crText);
if( nBreaks > 0 )
{
// draw start of line to first break
DrawScreenLine(
- pdc, origin, rc,
+ origin, rc,
blocks, nActualItem,
crText, crBkgnd, bDrawWhitespace,
pszChars, 0, anBreaks[0], nActualOffset, CPoint( 0, nLineIndex ) );
{
ASSERT( anBreaks[i] >= 0 && anBreaks[i] < nLength );
DrawScreenLine(
- pdc, origin, rc,
+ origin, rc,
blocks, nActualItem,
crText, crBkgnd, bDrawWhitespace,
pszChars, anBreaks[i], anBreaks[i + 1] - anBreaks[i],
// draw from last break till end of line
DrawScreenLine(
- pdc, origin, rc,
+ origin, rc,
blocks, nActualItem,
crText, crBkgnd, bDrawWhitespace,
pszChars, anBreaks[i], nLength - anBreaks[i],
}
else
DrawScreenLine(
- pdc, origin, rc,
+ origin, rc,
blocks, nActualItem,
crText, crBkgnd, bDrawWhitespace,
pszChars, 0, nLength, nActualOffset, CPoint(0, nLineIndex));
{
CRect frect = rc;
frect.top = frect.bottom - nEmptySubLines * GetLineHeight();
- pdc->FillSolidRect(frect, crBkgnd == CLR_NONE ? GetColor(COLORINDEX_WHITESPACE) : crBkgnd);
+ m_pCrystalRenderer->FillSolidRectangle(frect, crBkgnd == CLR_NONE ? GetColor(COLORINDEX_WHITESPACE) : crBkgnd);
}
}
* @param [in] nLineNumber Line number to display. if -1, it's not displayed.
*/
void CCrystalTextView::
-DrawMargin (CDC * pdc, const CRect & rect, int nLineIndex, int nLineNumber)
+DrawMargin (const CRect & rect, int nLineIndex, int nLineNumber)
{
if (!m_bSelMargin && !m_bViewLineNumbers)
- pdc->FillSolidRect (rect, GetColor (COLORINDEX_BKGND));
+ m_pCrystalRenderer->SetBkColor(GetColor (COLORINDEX_BKGND));
else
- pdc->FillSolidRect (rect, GetColor (COLORINDEX_SELMARGIN));
+ m_pCrystalRenderer->SetBkColor(GetColor (COLORINDEX_SELMARGIN));
+ m_pCrystalRenderer->FillRectangle(rect);
if (m_bViewLineNumbers && nLineNumber > 0)
{
- TCHAR szNumbers[32];
- wsprintf(szNumbers, _T("%d"), nLineNumber);
- CFont *pOldFont = pdc->SelectObject(GetFont());
- COLORREF clrOldColor = pdc->SetTextColor(GetColor(COLORINDEX_NORMALTEXT));
- UINT uiOldAlign = pdc->SetTextAlign(TA_RIGHT);
- pdc->TextOut(rect.right - (pdc->IsPrinting() ? 0 : 4), rect.top, szNumbers, lstrlen(szNumbers));
- pdc->SetTextAlign(uiOldAlign);
- pdc->SelectObject(pOldFont);
- pdc->SetTextColor(clrOldColor);
+ m_pCrystalRenderer->SetTextColor(GetColor(COLORINDEX_NORMALTEXT));
+ m_pCrystalRenderer->DrawMarginLineNumber(rect.right, rect.top, nLineNumber);
}
// Draw line revision mark (or background) whenever we have valid lineindex
}
// draw line revision marks
- CRect rc(rect.right - (pdc->IsPrinting () ? 0 : MARGIN_REV_WIDTH), rect.top, rect.right, rect.bottom);
- pdc->FillSolidRect (rc, clrRevisionMark);
+ CRect rc(rect.right - MARGIN_REV_WIDTH, rect.top, rect.right, rect.bottom);
+ m_pCrystalRenderer->FillSolidRectangle (rc, clrRevisionMark);
- if (!m_bSelMargin || pdc->IsPrinting ())
+ if (!m_bSelMargin)
return;
int nImageIndex = -1;
}
}
}
- if (m_pIcons == nullptr)
- {
- m_pIcons = new CImageList;
- VERIFY (m_pIcons->Create(MARGIN_ICON_WIDTH, MARGIN_ICON_HEIGHT,
- ILC_COLOR32 | ILC_MASK, 0, 1));
- CBitmap bmp;
- bmp.LoadBitmap(IDR_MARGIN_ICONS);
- m_pIcons->Add(&bmp, RGB(255, 255, 255));
- }
if (nImageIndex >= 0)
{
- CPoint pt(rect.left + 2, rect.top + (GetLineHeight() - MARGIN_ICON_HEIGHT) / 2);
- VERIFY(m_pIcons->Draw(pdc, nImageIndex, pt, ILD_TRANSPARENT));
- VERIFY (m_pIcons->Draw (pdc, nImageIndex, pt, ILD_TRANSPARENT));
+ m_pCrystalRenderer->DrawMarginIcon(
+ rect.left + 2, rect.top + (GetLineHeight() - CCrystalRenderer::MARGIN_ICON_HEIGHT) / 2, nImageIndex);
}
// draw wrapped-line-icon
WrapLineCached( nLineIndex, GetScreenChars(), nullptr, nBreaks );
for (int i = 0; i < nBreaks; i++)
{
- CPoint pt(rect.right - MARGIN_ICON_WIDTH, rect.top + (GetLineHeight()
- - MARGIN_ICON_WIDTH) / 2 + (i+1) * GetLineHeight());
- m_pIcons->Draw (pdc, ICON_INDEX_WRAPLINE, pt, ILD_TRANSPARENT);
+ m_pCrystalRenderer->DrawMarginIcon(
+ rect.right - CCrystalRenderer::MARGIN_ICON_WIDTH, rect.top + (GetLineHeight()
+ - CCrystalRenderer::MARGIN_ICON_WIDTH) / 2 + (i+1) * GetLineHeight(), ICON_INDEX_WRAPLINE);
}
}
}
-void CCrystalTextView::
-DrawBoundaryLine (CDC * pdc, int nLeft, int nRight, int y)
-{
- CPen *pOldPen = (CPen *)pdc->SelectStockObject (BLACK_PEN);
- pdc->MoveTo (nLeft, y);
- pdc->LineTo (nRight, y);
- pdc->SelectObject (pOldPen);
-}
-
-void CCrystalTextView::
-DrawLineCursor (CDC * pdc, int nLeft, int nRight, int y, int nHeight)
-{
- CDC dcMem;
- dcMem.CreateCompatibleDC (pdc);
- CBitmap bitmap;
- bitmap.CreateCompatibleBitmap (pdc, nRight - nLeft, nHeight);
- CBitmap *pOldBitmap = dcMem.SelectObject (&bitmap);
- dcMem.SetBkColor(RGB(0, 255, 0));
- BLENDFUNCTION blend = {0};
- blend.BlendOp = AC_SRC_OVER;
- blend.SourceConstantAlpha = 24;
- pdc->AlphaBlend (nLeft, y, nRight - nLeft, nHeight, &dcMem, 0, 0, nRight - nLeft, nHeight, blend);
- dcMem.SelectObject (pOldBitmap);
-}
-
bool CCrystalTextView::
IsInsideSelBlock (CPoint ptTextPos)
{
if (m_pTextBuffer == nullptr)
{
- pdc->FillSolidRect(&rcClient, GetSysColor(COLOR_WINDOW));
+ m_pCrystalRenderer->BindDC(*pdc, rcClient);
+ m_pCrystalRenderer->BeginDraw();
+ m_pCrystalRenderer->SetBkColor(GetSysColor(COLOR_WINDOW));
+ m_pCrystalRenderer->FillRectangle(rcClient);
+ m_pCrystalRenderer->EndDraw();
return;
}
}
CBitmap *pOldBitmap = cacheDC.SelectObject (m_pCacheBitmap);
- CRect rcLine;
- rcLine = rcClient;
- rcLine.bottom = rcLine.top + nLineHeight;
- CRect rcCacheMargin (0, 0, GetMarginWidth (), nLineHeight);
- CRect rcCacheLine (GetMarginWidth (), 0, rcLine.Width (), nLineHeight);
- //BEGIN SW
// initialize rects
- int nSubLineOffset = GetSubLineIndex( m_nTopLine ) - m_nTopSubLine;
- if( nSubLineOffset < 0 )
- {
- rcCacheMargin.OffsetRect( 0, nSubLineOffset * nLineHeight );
- rcCacheLine.OffsetRect( 0, nSubLineOffset * nLineHeight );
- }
-
+ int nSubLineOffset = GetSubLineIndex( m_nTopLine ) - m_nTopSubLine;
int nCursorY = TextToClient (m_ptCursorPos).y;
- //END SW
+ CRect rcLine;
+ rcLine = rcClient;
+ rcLine.top += nSubLineOffset * nLineHeight;
+ CRect rcMargin (rcLine.left, rcLine.top, rcLine.left + GetMarginWidth (), rcLine.top + nLineHeight);
+ rcLine.left = rcMargin.right;
+
+ m_pCrystalRenderer->BindDC(cacheDC, rcClient);
+ m_pCrystalRenderer->BeginDraw();
int nCurrentLine = m_nTopLine;
while (rcLine.top < rcClient.bottom)
{
- //BEGIN SW
int nSubLines = 1;
if( nCurrentLine < nLineCount /*&& GetLineLength( nCurrentLine ) > nMaxLineChars*/ )
nSubLines = GetSubLines(nCurrentLine);
rcLine.bottom = rcLine.top + nSubLines * nLineHeight;
- rcCacheLine.bottom = rcCacheLine.top + rcLine.Height();
- rcCacheMargin.bottom = rcCacheMargin.top + rcLine.Height();
+ rcMargin.bottom = rcLine.bottom;
- if( rcCacheLine.top < 0 )
- rcLine.bottom+= rcCacheLine.top;
- //END SW
- if (pdc->RectVisible(rcLine))
+ CRect rcMarginAndLine(rcClient.left, rcLine.top, rcClient.right, rcLine.bottom);
+ if (pdc->RectVisible(rcMarginAndLine))
{
if (nCurrentLine < nLineCount && GetLineVisible (nCurrentLine))
{
- DrawMargin (&cacheDC, rcCacheMargin, nCurrentLine, nCurrentLine + 1);
- DrawSingleLine (&cacheDC, rcCacheLine, nCurrentLine);
+ DrawMargin (rcMargin, nCurrentLine, nCurrentLine + 1);
+ DrawSingleLine (rcLine, nCurrentLine);
if (nCurrentLine+1 < nLineCount && !GetLineVisible (nCurrentLine + 1))
- DrawBoundaryLine (&cacheDC, rcCacheMargin.left, rcCacheLine.right, rcCacheMargin.bottom-1);
+ m_pCrystalRenderer->DrawBoundaryLine (rcMargin.left, rcLine.right, rcMargin.bottom-1);
if (nCurrentLine == m_ptCursorPos.y)
- DrawLineCursor (&cacheDC, rcCacheMargin.left, rcCacheLine.right,
- nCursorY - rcLine.top + nLineHeight - 1, 1);
+ m_pCrystalRenderer->DrawLineCursor (rcMargin.left, rcLine.right,
+ nCursorY + nLineHeight - 1, 1);
}
else
{
- DrawMargin (&cacheDC, rcCacheMargin, -1, -1);
- DrawSingleLine (&cacheDC, rcCacheLine, -1);
+ DrawMargin (rcMargin, -1, -1);
+ DrawSingleLine (rcLine, -1);
}
-
- VERIFY (pdc->BitBlt (rcLine.left, rcLine.top, rcLine.Width (),
- rcLine.Height (), &cacheDC, 0, 0, SRCCOPY));
}
nCurrentLine++;
- //BEGIN SW
rcLine.top = rcLine.bottom;
- rcCacheLine.top = 0;
- rcCacheMargin.top = 0;
- /*ORIGINAL
- rcLine.OffsetRect(0, nLineHeight);
- */
- //END SW
+ rcMargin.top = rcLine.top;
}
+ m_pCrystalRenderer->EndDraw();
+
+ VERIFY (pdc->BitBlt (rcClient.left, rcClient.top, rcClient.Width (),
+ rcClient.Height (), &cacheDC, 0, 0, SRCCOPY));
+
cacheDC.SelectObject (pOldBitmap);
cacheDC.DeleteDC ();
}
m_nIdealCharPos = -1;
m_ptAnchor.x = 0;
m_ptAnchor.y = 0;
- if (m_pIcons != nullptr)
- {
- delete m_pIcons;
- m_pIcons = nullptr;
- }
- for (int I = 0; I < 4; I++)
- {
- if (m_apFonts[I] != nullptr)
- {
- delete m_apFonts[I];
- m_apFonts[I] = nullptr;
- }
- }
InvalidateLineCache( 0, -1 );
m_ParseCookies->clear();
m_pnActualLineLength->clear();
}
}
-CFont *CCrystalTextView::
-GetFont (bool bItalic /*= false*/ , bool bBold /*= false*/ )
-{
- int nIndex = 0;
- if (bBold)
- nIndex |= 1;
- if (bItalic)
- nIndex |= 2;
-
- if (m_apFonts[nIndex] == nullptr)
- {
- m_apFonts[nIndex] = new CFont;
- if (!m_lfBaseFont.lfHeight)
- {
- CClientDC dc (GetDesktopWindow ());
- m_lfBaseFont.lfHeight = -MulDiv (11, dc.GetDeviceCaps (LOGPIXELSY), 72);
- }
- m_lfBaseFont.lfWeight = bBold ? FW_BOLD : FW_NORMAL;
- m_lfBaseFont.lfItalic = (BYTE) bItalic;
- if (!m_apFonts[nIndex]->CreateFontIndirect (&m_lfBaseFont))
- {
- delete m_apFonts[nIndex];
- m_apFonts[nIndex] = nullptr;
- return CView::GetFont ();
- }
- }
- return m_apFonts[nIndex];
-}
-
void CCrystalTextView::
CalcLineCharDim ()
{
- CDC *pdc = GetDC ();
- CFont *pOldFont = pdc->SelectObject (GetFont ());
- CSize szCharExt = pdc->GetTextExtent (_T ("X"));
+ CSize szCharExt = m_pCrystalRenderer->GetCharWidthHeight();
m_nLineHeight = szCharExt.cy;
if (m_nLineHeight < 1)
m_nLineHeight = 1;
m_nCharWidth = szCharExt.cx;
- /*
- TEXTMETRIC tm;
- if (pdc->GetTextMetrics(&tm))
- m_nCharWidth -= tm.tmOverhang;
- */
- pdc->SelectObject (GetFont (false, true));
- szCharExt = pdc->GetTextExtent (_T ("X"));
- if (m_nLineHeight < szCharExt.cy)
- m_nLineHeight = szCharExt.cy;
- pdc->SelectObject (pOldFont);
- ReleaseDC (pdc);
}
int CCrystalTextView::
OnBeginPrinting (CDC * pdc, CPrintInfo * pInfo)
{
ASSERT (m_pPrintFont == nullptr);
- CFont *pDisplayFont = GetFont ();
-
- LOGFONT lf;
+ LOGFONT lf = m_lfBaseFont;
CDC *pDisplayDC = GetDC ();
- pDisplayFont->GetLogFont (&lf);
lf.lfHeight = MulDiv (lf.lfHeight, pdc->GetDeviceCaps (LOGPIXELSY), pDisplayDC->GetDeviceCaps (LOGPIXELSY));
lf.lfWidth = MulDiv (lf.lfWidth, pdc->GetDeviceCaps (LOGPIXELSX), pDisplayDC->GetDeviceCaps (LOGPIXELSX));
ReleaseDC (pDisplayDC);
rcLine.OffsetRect( 0, nSubLineOffset * nLineHeight );
}
+ m_pCrystalRenderer->BindDC(*pdc, m_rcPrintArea);
+ m_pCrystalRenderer->BeginDraw();
+
int nLineCount = GetLineCount();
int nCurrentLine;
for (nCurrentLine = nTopLine; nCurrentLine <= nEndLine; nCurrentLine++)
if (nCurrentLine < nLineCount && GetLineVisible (nCurrentLine))
{
- DrawMargin (pdc, rcMargin, nCurrentLine, nCurrentLine + 1);
- DrawSingleLine (pdc, rcLine, nCurrentLine);
+ DrawMargin (rcMargin, nCurrentLine, nCurrentLine + 1);
+ DrawSingleLine (rcLine, nCurrentLine);
if (nCurrentLine+1 < nLineCount && !GetLineVisible (nCurrentLine + 1))
- DrawBoundaryLine (pdc, rcMargin.left, rcLine.right, rcMargin.bottom-1);
+ m_pCrystalRenderer->DrawBoundaryLine (rcMargin.left, rcLine.right, rcMargin.bottom-1);
}
rcLine.top = rcLine.bottom;
rcMargin.top = rcLine.bottom;
}
+ m_pCrystalRenderer->EndDraw();
+
pdc->SelectClipRgn (nullptr);
}
void CCrystalTextView::
OnDestroy ()
{
- GetFont ()->GetLogFont (&m_lfBaseFont);
DetachFromBuffer ();
m_hAccel = nullptr;
CView::OnDestroy ();
- for (int I = 0; I < 4; I++)
- {
- if (m_apFonts[I] != nullptr)
- {
- delete m_apFonts[I];
- m_apFonts[I] = nullptr;
- }
- }
if (m_pCacheBitmap != nullptr)
{
delete m_pCacheBitmap;
UpdateCompositionWindowFont() /* IME */
{
HIMC hIMC = ImmGetContext(m_hWnd);
- LOGFONT logfont;
- GetFont()->GetLogFont(&logfont);
- ImmSetCompositionFont(hIMC, &logfont);
+ ImmSetCompositionFont(hIMC, &m_lfBaseFont);
ImmReleaseContext(m_hWnd, hIMC);
}
m_lfBaseFont = lf;
m_nCharWidth = -1;
m_nLineHeight = -1;
- for (int I = 0; I < 4; I++)
- {
- if (m_apFonts[I] != nullptr)
- {
- delete m_apFonts[I];
- m_apFonts[I] = nullptr;
- }
- }
+ m_pCrystalRenderer->SetFont(lf);
if (::IsWindow (m_hWnd))
{
InvalidateScreenRect();
Invalidate ();
}
+void CCrystalTextView::SetRenderingMode(RENDERING_MODE nRenderingMode)
+{
+#ifdef _WIN64
+ if (nRenderingMode == RENDERING_MODE_GDI)
+ m_pCrystalRenderer.reset(new CCrystalRendererGDI());
+ else
+ m_pCrystalRenderer.reset(new CCrystalRendererDirectWrite(nRenderingMode));
+ m_pCrystalRenderer->SetFont(m_lfBaseFont);
+#endif
+ m_nRenderingMode = nRenderingMode;
+}
+
//BEGIN SW
bool CCrystalTextView::GetWordWrapping() const
{
int nWidthArray[256];
wchar_t nStart = ch/256*256;
wchar_t nEnd = nStart + 255;
- CDC *pdc = GetDC();
- CFont *pOldFont = pdc->SelectObject(GetFont());
- GetCharWidth32(pdc->m_hDC, nStart, nEnd, nWidthArray);
+ m_pCrystalRenderer->GetCharWidth(nStart, nEnd, nWidthArray);
int nCharWidth = GetCharWidth();
for (int i = 0; i < 256; i++)
{
}
}
m_bChWidthsCalculated[ch / 256] = true;
- pdc->SelectObject(pOldFont);
}
}
if (m_iChDoubleWidthFlags[ch / 32] & (1 << (ch % 32)))
#include "cregexp.h"
#include "crystalparser.h"
#include "crystallineparser.h"
+#include "ccrystalrenderer.h"
#include "icu.hpp"
////////////////////////////////////////////////////////////////////////////
private:
LOGFONT m_lfBaseFont;
LOGFONT m_lfSavedBaseFont;
- CFont *m_apFonts[4];
// Parsing stuff
int ApproxActualOffset (int nLineIndex, int nOffset);
void AdjustTextPoint (CPoint & point);
- void DrawLineHelperImpl (CDC * pdc, CPoint & ptOrigin, const CRect & rcClip,
- int nColorIndex, int nBgColorIndex, COLORREF crText, COLORREF crBkgnd, LPCTSTR pszChars, int nOffset, int nCount, int &nActualOffset);
+ void DrawLineHelperImpl (CPoint & ptOrigin, const CRect & rcClip,
+ int nColorIndex,
+ int nBgColorIndex, COLORREF crText, COLORREF crBkgnd, LPCTSTR pszChars, int nOffset, int nCount, int &nActualOffset);
bool IsInsideSelBlock (CPoint ptTextPos);
bool m_bBookmarkExist; // More bookmarks
void ToggleBookmark(int nLine);
public :
+ enum RENDERING_MODE
+ {
+ RENDERING_MODE_GDI = -1,
+ RENDERING_MODE_DWRITE_DFEAULT = 0,
+ RENDERING_MODE_DWRITE_ALIASED = 1,
+ RENDERING_MODE_DWRITE_GDI_CLASSIC = 2,
+ RENDERING_MODE_DWRITE_GDI_NATURAL = 3,
+ RENDERING_MODE_DWRITE_NATURAL = 4,
+ RENDERING_MODE_DWRITE_NATURAL_SYMMETRIC = 5,
+ };
+
virtual void ResetView ();
virtual int GetLineCount ();
virtual void OnUpdateCaret ();
bool m_bOverrideCaret;
bool m_bSingle;
- CImageList * m_pIcons;
CCrystalTextBuffer *m_pTextBuffer;
HACCEL m_hAccel;
bool m_bVertScrollBarLocked, m_bHorzScrollBarLocked;
int GetMaxLineLength (int nTopLine, int nLines);
int GetScreenLines ();
int GetScreenChars ();
- CFont *GetFont (bool bItalic = false, bool bBold = false);
void RecalcVertScrollBar (bool bPositionOnly = false, bool bRedraw = true);
virtual void RecalcHorzScrollBar (bool bPositionOnly = false, bool bRedraw = true);
virtual bool GetItalic (int nColorIndex);
virtual bool GetBold (int nColorIndex);
- void DrawLineHelper (CDC * pdc, CPoint & ptOrigin, const CRect & rcClip, int nColorIndex, int nBgColorIndex,
+ void DrawLineHelper (CPoint & ptOrigin, const CRect & rcClip, int nColorIndex, int nBgColorIndex,
COLORREF crText, COLORREF crBkgnd, LPCTSTR pszChars, int nOffset, int nCount, int &nActualOffset, CPoint ptTextPos);
- virtual void DrawSingleLine (CDC * pdc, const CRect & rect, int nLineIndex);
- virtual void DrawMargin (CDC * pdc, const CRect & rect, int nLineIndex, int nLineNumber);
- virtual void DrawBoundaryLine (CDC * pdc, int nLeft, int nRight, int y);
- virtual void DrawLineCursor (CDC * pdc, int nLeft, int nRight, int y, int nHeight);
+ virtual void DrawSingleLine (const CRect & rect, int nLineIndex);
+ virtual void DrawMargin (const CRect & rect, int nLineIndex, int nLineNumber);
inline int GetCharCellCountFromChar(const TCHAR *pch)
{
//BEGIN SW
// function to draw a single screen line
// (a wrapped line can consist of many screen lines
- virtual void DrawScreenLine( CDC *pdc, CPoint &ptOrigin, const CRect &rcClip,
- const std::vector<CrystalLineParser::TEXTBLOCK>& blocks, int &nActualItem,
- COLORREF crText, COLORREF crBkgnd, bool bDrawWhitespace,
- LPCTSTR pszChars,
- int nOffset, int nCount, int &nActualOffset, CPoint ptTextPos );
+ virtual void DrawScreenLine( CPoint &ptOrigin, const CRect &rcClip,
+ const std::vector<CrystalLineParser::TEXTBLOCK>& blocks,
+ int &nActualItem,
+ COLORREF crText,
+ COLORREF crBkgnd, bool bDrawWhitespace,
+ LPCTSTR pszChars,
+
+ int nOffset,
+ int nCount, int &nActualOffset, CPoint ptTextPos );
//END SW
std::vector<CrystalLineParser::TEXTBLOCK> MergeTextBlocks(const std::vector<CrystalLineParser::TEXTBLOCK>& blocks1, const std::vector<CrystalLineParser::TEXTBLOCK>& blocks2) const;
bool GetDisableDragAndDrop () const;
void SetDisableDragAndDrop (bool bDDAD);
+ static RENDERING_MODE GetRenderingModeDefault() { return s_nRenderingModeDefault; }
+ static void SetRenderingModeDefault(RENDERING_MODE nRenderingMode) { s_nRenderingModeDefault = nRenderingMode; }
+ RENDERING_MODE GetRenderingMode() const { return m_nRenderingMode; }
+ void SetRenderingMode(RENDERING_MODE nRenderingMode);
+
//BEGIN SW
bool GetWordWrapping() const;
virtual void SetWordWrapping( bool bWordWrap );
RxMatchRes m_rxmatch;
LPTSTR m_pszMatched;
static LOGFONT m_LogFont;
+ static RENDERING_MODE s_nRenderingModeDefault;
+ RENDERING_MODE m_nRenderingMode;
ICUBreakIterator m_iterChar;
ICUBreakIterator m_iterWord;
+ std::unique_ptr<CCrystalRenderer> m_pCrystalRenderer;
typedef enum
{
* @param [in] nLineIndex Index of line in view.
* @param [in] nLineNumber Line number to display. if -1, it's not displayed.
*/
-void CGhostTextView::DrawMargin (CDC * pdc, const CRect & rect, int nLineIndex, int nLineNumber)
+void CGhostTextView::DrawMargin (const CRect & rect, int nLineIndex, int nLineNumber)
{
int nRealLineNumber;
if (nLineIndex < 0 || GetLineFlags(nLineIndex) & LF_GHOST)
nRealLineNumber = -1;
else
nRealLineNumber = ComputeRealLine(nLineIndex) + 1;
- CCrystalTextView::DrawMargin(pdc, rect, nLineIndex, nRealLineNumber);
+ CCrystalTextView::DrawMargin(rect, nLineIndex, nRealLineNumber);
}
int ComputeApparentLine (int nRealLine) const;
int ComputeRealLine (int nApparentLine) const;
- virtual void DrawMargin (CDC * pdc, const CRect & rect, int nLineIndex, int nLineNumber) override;
+ virtual void DrawMargin (const CRect & rect, int nLineIndex, int nLineNumber) override;
};
String filterPath = GetOptionsMgr()->GetString(OPT_FILTER_USERPATH);
theApp.m_pGlobalFileFilter->SetUserFilterPath(filterPath);
+ CCrystalTextView::RENDERING_MODE nRenderingMode = static_cast<CCrystalTextView::RENDERING_MODE>(GetOptionsMgr()->GetInt(OPT_RENDERING_MODE));
+ CCrystalTextView::SetRenderingModeDefault(nRenderingMode);
+
theApp.UpdateCodepageModule();
strdiff::SetBreakChars(GetOptionsMgr()->GetString(OPT_BREAK_SEPARATORS).c_str());
if (m_pMarkers != nullptr)
m_pMarkers->LoadFromRegistry();
+ CCrystalTextView::SetRenderingModeDefault(static_cast<CCrystalTextView::RENDERING_MODE>(GetOptionsMgr()->GetInt(OPT_RENDERING_MODE)));
+
if (m_pLineFilters != nullptr)
m_pLineFilters->Initialize(GetOptionsMgr());
COMBOBOX IDC_BREAK_TYPE,38,162,183,34,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP\r
LTEXT "W&ord break characters:",IDC_STATIC,24,180,194,10\r
EDITTEXT IDC_BREAK_CHARS,24,192,198,14,ES_AUTOHSCROLL\r
+ LTEXT "&Rendering Mode:",IDC_STATIC,7,220,90,10\r
+ COMBOBOX IDC_RENDERING_MODE,100,220,148,34,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP\r
END\r
\r
IDD_MESSAGE_BOX DIALOGEX 0, 0, 186, 95\r
<ProjectGuid>{9FDA4AF0-CCFD-4812-BDB9-53EFEDB32BDE}</ProjectGuid>\r
<RootNamespace>Merge</RootNamespace>\r
<Keyword>MFCProj</Keyword>\r
- <WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>\r
+ <WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>\r
</PropertyGroup>\r
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
<ConfigurationType>Application</ConfigurationType>\r
<UseOfMfc>Static</UseOfMfc>\r
<CharacterSet>Unicode</CharacterSet>\r
- <PlatformToolset>v141</PlatformToolset>\r
+ <PlatformToolset>v141_xp</PlatformToolset>\r
<XPDeprecationWarning>false</XPDeprecationWarning>\r
</PropertyGroup>\r
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
<ConfigurationType>Application</ConfigurationType>\r
<UseOfMfc>Static</UseOfMfc>\r
<CharacterSet>Unicode</CharacterSet>\r
- <PlatformToolset>v141_xp</PlatformToolset>\r
+ <PlatformToolset>v141</PlatformToolset>\r
<XPDeprecationWarning>false</XPDeprecationWarning>\r
</PropertyGroup>\r
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Test|x64'" Label="Configuration">\r
<ConfigurationType>Application</ConfigurationType>\r
<UseOfMfc>Static</UseOfMfc>\r
<CharacterSet>Unicode</CharacterSet>\r
- <PlatformToolset>v141_xp</PlatformToolset>\r
+ <PlatformToolset>v141</PlatformToolset>\r
<XPDeprecationWarning>false</XPDeprecationWarning>\r
</PropertyGroup>\r
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
<ClCompile Include="..\Externals\crystaledit\editlib\basic.cpp" />\r
<ClCompile Include="..\Externals\crystaledit\editlib\batch.cpp" />\r
<ClCompile Include="..\Externals\crystaledit\editlib\ccrystaleditview.cpp" />\r
+ <ClCompile Include="..\Externals\crystaledit\editlib\ccrystalrendererdirectwrite.cpp">\r
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>\r
+ </ClCompile>\r
+ <ClCompile Include="..\Externals\crystaledit\editlib\ccrystalrenderergdi.cpp" />\r
<ClCompile Include="..\Externals\crystaledit\editlib\ccrystaltextbuffer.cpp" />\r
<ClCompile Include="..\Externals\crystaledit\editlib\ccrystaltextmarkers.cpp" />\r
<ClCompile Include="..\Externals\crystaledit\editlib\ccrystaltextview.cpp" />\r
<ClInclude Include="..\Externals\boost\boost\config\compiler\visualc.hpp" />\r
<ClInclude Include="..\Externals\boost\boost\config\select_compiler_config.hpp" />\r
<ClInclude Include="..\Externals\crystaledit\editlib\ccrystaleditview.h" />\r
+ <ClInclude Include="..\Externals\crystaledit\editlib\ccrystalrenderer.h" />\r
+ <ClInclude Include="..\Externals\crystaledit\editlib\ccrystalrendererdirectwrite.h" />\r
+ <ClInclude Include="..\Externals\crystaledit\editlib\ccrystalrenderergdi.h" />\r
<ClInclude Include="..\Externals\crystaledit\editlib\ccrystaltextbuffer.h" />\r
<ClInclude Include="..\Externals\crystaledit\editlib\ccrystaltextmarkers.h" />\r
<ClInclude Include="..\Externals\crystaledit\editlib\ccrystaltextview.h" />\r
<ClCompile Include="..\Externals\crystaledit\editlib\icu.cpp">\r
<Filter>EditLib\Source Files</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\Externals\crystaledit\editlib\ccrystalrenderergdi.cpp">\r
+ <Filter>EditLib\Source Files</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\Externals\crystaledit\editlib\ccrystalrendererdirectwrite.cpp">\r
+ <Filter>EditLib\Source Files</Filter>\r
+ </ClCompile>\r
<ClCompile Include="DirSelectFilesDlg.cpp">\r
<Filter>MFCGui\Dialogs\Source Files</Filter>\r
</ClCompile>\r
<ClCompile Include="..\Externals\crystaledit\editlib\basic.cpp" />\r
<ClCompile Include="..\Externals\crystaledit\editlib\batch.cpp" />\r
<ClCompile Include="..\Externals\crystaledit\editlib\ccrystaleditview.cpp" />\r
+ <ClCompile Include="..\Externals\crystaledit\editlib\ccrystalrendererdirectwrite.cpp">\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Test|Win32'">NotUsing</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Test|x64'">NotUsing</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>\r
+ </ClCompile>\r
+ <ClCompile Include="..\Externals\crystaledit\editlib\ccrystalrenderergdi.cpp" />\r
<ClCompile Include="..\Externals\crystaledit\editlib\ccrystaltextbuffer.cpp" />\r
<ClCompile Include="..\Externals\crystaledit\editlib\ccrystaltextmarkers.cpp" />\r
<ClCompile Include="..\Externals\crystaledit\editlib\ccrystaltextview.cpp" />\r
<ClInclude Include="..\Externals\boost\boost\config\compiler\visualc.hpp" />\r
<ClInclude Include="..\Externals\boost\boost\config\select_compiler_config.hpp" />\r
<ClInclude Include="..\Externals\crystaledit\editlib\ccrystaleditview.h" />\r
+ <ClInclude Include="..\Externals\crystaledit\editlib\ccrystalrenderer.h" />\r
+ <ClInclude Include="..\Externals\crystaledit\editlib\ccrystalrendererdirectwrite.h" />\r
+ <ClInclude Include="..\Externals\crystaledit\editlib\ccrystalrenderergdi.h" />\r
<ClInclude Include="..\Externals\crystaledit\editlib\ccrystaltextbuffer.h" />\r
<ClInclude Include="..\Externals\crystaledit\editlib\ccrystaltextmarkers.h" />\r
<ClInclude Include="..\Externals\crystaledit\editlib\ccrystaltextview.h" />\r
<ClCompile Include="..\Externals\crystaledit\editlib\icu.cpp">\r
<Filter>EditLib\Source Files</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\Externals\crystaledit\editlib\ccrystalrenderergdi.cpp">\r
+ <Filter>EditLib\Source Files</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\Externals\crystaledit\editlib\ccrystalrendererdirectwrite.cpp">\r
+ <Filter>EditLib\Source Files</Filter>\r
+ </ClCompile>\r
<ClCompile Include="DirSelectFilesDlg.cpp">\r
<Filter>MFCGui\Dialogs\Source Files</Filter>\r
</ClCompile>\r
IDR_SPLASH IMAGE "res\\splash.jpg"
IDR_LOGO IMAGE "res\\logo.jpg"
+IDR_MARGIN_ICONS_PNG IMAGE "res\\mg_icons.png"
/////////////////////////////////////////////////////////////////////////////
*/
void CMergeEditView::RefreshOptions()
{
+ RENDERING_MODE nRenderingMode = static_cast<RENDERING_MODE>(GetOptionsMgr()->GetInt(OPT_RENDERING_MODE));
+ SetRenderingMode(nRenderingMode);
+
m_bAutomaticRescan = GetOptionsMgr()->GetBool(OPT_AUTOMATIC_RESCAN);
if (GetOptionsMgr()->GetInt(OPT_TAB_TYPE) == 0)
extern const String OPT_VIEW_WHITESPACE OP("Settings/ViewWhitespace");
extern const String OPT_CONNECT_MOVED_BLOCKS OP("Settings/ConnectMovedBlocks");
extern const String OPT_SCROLL_TO_FIRST OP("Settings/ScrollToFirst");
+extern const String OPT_RENDERING_MODE OP("Settings/RenderingMode");
// Difference (in-line) highlight
extern const String OPT_WORDDIFF_HIGHLIGHT OP("Settings/HiliteWordDiff");
pOptions->InitOption(OPT_VIEW_FILEMARGIN, false);
pOptions->InitOption(OPT_DIFF_CONTEXT, (int)-1);
pOptions->InitOption(OPT_SPLIT_HORIZONTALLY, false);
+ pOptions->InitOption(OPT_RENDERING_MODE, -1);
pOptions->InitOption(OPT_WORDDIFF_HIGHLIGHT, true);
pOptions->InitOption(OPT_BREAK_SEPARATORS, _T(".,:;?[](){}<>`'!\"#$%&^~\\|@+-*/"));
, m_bViewLineDifferences(false)
, m_bBreakOnWords(false)
, m_nBreakType(0)
+, m_nRenderingMode(0)
{
}
DDX_Radio(pDX, IDC_EDITOR_CHARLEVEL, m_bBreakOnWords);
DDX_CBIndex(pDX, IDC_BREAK_TYPE, m_nBreakType);
DDX_Text(pDX, IDC_BREAK_CHARS, m_breakChars);
+ DDX_CBIndex(pDX, IDC_RENDERING_MODE, m_nRenderingMode);
//}}AFX_DATA_MAP
}
m_bBreakOnWords = GetOptionsMgr()->GetBool(OPT_BREAK_ON_WORDS);
m_nBreakType = GetOptionsMgr()->GetInt(OPT_BREAK_TYPE);
m_breakChars = GetOptionsMgr()->GetString(OPT_BREAK_SEPARATORS);
+ m_nRenderingMode = GetOptionsMgr()->GetInt(OPT_RENDERING_MODE) + 1;
}
/**
GetOptionsMgr()->SaveOption(OPT_BREAK_ON_WORDS, m_bBreakOnWords);
GetOptionsMgr()->SaveOption(OPT_BREAK_TYPE, m_nBreakType);
GetOptionsMgr()->SaveOption(OPT_BREAK_SEPARATORS, String(m_breakChars));
+ GetOptionsMgr()->SaveOption(OPT_RENDERING_MODE, m_nRenderingMode - 1);
}
/**
{
OptionsPanel::OnInitDialog();
- LoadBreakTypeStrings();
+ LoadComboBoxStrings();
UpdateDataToWindow();
UpdateLineDiffControls();
/**
* @brief Load strings (from resource) into combobox for break type
*/
-void PropEditor::LoadBreakTypeStrings()
+void PropEditor::LoadComboBoxStrings()
{
CComboBox * cbo = (CComboBox *)GetDlgItem(IDC_BREAK_TYPE);
cbo->AddString(_("Break at whitespace").c_str());
cbo->AddString(_("Break at whitespace or punctuation").c_str());
+ cbo = (CComboBox *)GetDlgItem(IDC_RENDERING_MODE);
+ cbo->AddString(_("GDI").c_str());
+ cbo->AddString(_("DirectWrite Default").c_str());
+ cbo->AddString(_("DirectWrite Aliased").c_str());
+ cbo->AddString(_("DirectWrite GDI Classic").c_str());
+ cbo->AddString(_("DirectWrite GDI Natural").c_str());
+ cbo->AddString(_("DirectWrite Natural").c_str());
+ cbo->AddString(_("DirectWrite Natural Symmetric").c_str());
}
/**
bool m_bBreakOnWords;
int m_nBreakType;
String m_breakChars;
+ int m_nRenderingMode;
//}}AFX_DATA
private:
// Implementation methods
- void LoadBreakTypeStrings();
+ void LoadComboBoxStrings();
void UpdateDataToWindow() { UpdateData(FALSE); }
void UpdateDataFromWindow() { UpdateData(TRUE); }
void UpdateLineDiffControls();
#define IDR_LOGO 307\r
#define IDR_SPLASH 308\r
#define IDB_WINMERGE 309\r
+#define IDR_MARGIN_ICONS_PNG 310\r
#define IDB_EDIT_COPY 316\r
#define IDB_EDIT_CUT 317\r
#define IDB_EDIT_PASTE 318\r
#define IDC_USE_DIR_COMPARE_COLORS 1364\r
#define IDC_PLUGIN_FILEFILTERS 1365\r
#define IDC_PLUGIN_FILEFILTERS_DEFAULTS 1366\r
+#define IDC_RENDERING_MODE 1367\r
#define IDC_DIFF_IGNORECP 1377\r
#define IDC_RESET 1378\r
#define IDC_LEFT1 1379\r
msgid "W&ord break characters:"
msgstr ""
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Agiri-iragazkiak"
msgid "W&ord break characters:"
msgstr "C&aracters da quebra de linha:"
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Filtros dos arquivos"
msgid "W&ord break characters:"
msgstr "Символ за пренасяне на &дума:"
+msgid "&Rendering Mode:"
+msgstr ""
+
msgid "Filefilters"
msgstr "Филтри за файлове"
msgid "W&ord break characters:"
msgstr ""
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Filtres de fitxer"
msgid "W&ord break characters:"
msgstr "单词分隔字符:"
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "文件过滤器"
msgid "W&ord break characters:"
msgstr "斷句字元(&O):"
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "檔案篩選器"
msgid "W&ord break characters:"
msgstr ""
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Filtar redaka"
msgid "W&ord break characters:"
msgstr "Zn&aky oddělující slova:"
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Filtrování souborů"
msgid "W&ord break characters:"
msgstr ""
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Filfiltre"
msgid "W&ord break characters:"
msgstr "Woordsplitsingstekens:"
+msgid "&Rendering Mode:"
+msgstr ""
+
msgid "Filefilters"
msgstr "Bestandsfilters"
msgid "W&ord break characters:"
msgstr ""
+msgid "&Rendering Mode:"
+msgstr ""
+
msgid "Filefilters"
msgstr ""
msgid "W&ord break characters:"
msgstr ""
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Tiedostosuodattimet"
msgid "W&ord break characters:"
msgstr "Caractères pour distinction de mot :"
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Filtre des fichiers"
msgid "W&ord break characters:"
msgstr ""
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Filtros de arquivos"
msgid "W&ord break characters:"
msgstr "W&ortumbruchzeichen:"
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Dateifilter"
msgid "W&ord break characters:"
msgstr ""
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Αρχειοφίλτρα"
msgid "W&ord break characters:"
msgstr ""
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "FájlSzűrők"
msgid "W&ord break characters:"
msgstr "Caratteri terminatori &parola:"
+msgid "&Rendering Mode:"
+msgstr ""
+
msgid "Filefilters"
msgstr "Filtri file"
msgid "W&ord break characters:"
msgstr "単語区切り文字(&O)"
+msgid "&Rendering Mode:"
+msgstr "レンダリングモード(&R):"
+
msgid "Filefilters"
msgstr "ファイル フィルタ"
msgid "W&ord break characters:"
msgstr "단어 분리 문자(&O):"
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "파일 필터"
msgid "W&ord break characters:"
msgstr "Ž&odžių skirtukų simboliai:"
+msgid "&Rendering Mode:"
+msgstr ""
+
msgid "Filefilters"
msgstr "Failo filtrai"
msgid "W&ord break characters:"
msgstr ""
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Filfiltere"
msgid "W&ord break characters:"
msgstr ""
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr " پرونده صافيها "
msgid "W&ord break characters:"
msgstr "Znaki łamania wyrazów:"
+msgid "&Rendering Mode:"
+msgstr ""
+
+#, c-format
msgid "Filefilters"
msgstr "Filtry plików"
msgid "W&ord break characters:"
msgstr "Caracteres da palavra:"
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Filtros de ficheiro"
msgid "W&ord break characters:"
msgstr ""
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Filtre fişiere"
msgid "W&ord break characters:"
msgstr "Символы разрыва слова:"
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Фильтры файлов"
msgid "W&ord break characters:"
msgstr ""
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Филтер датотека"
msgid "W&ord break characters:"
msgstr ""
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "ගොනුපෙරහන්"
msgid "W&ord break characters:"
msgstr "Zalam&ovať slová:"
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Filtre súborov"
msgid "W&ord break characters:"
msgstr "&Znak za konec besede"
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Datotečni filtri"
msgid "W&ord break characters:"
msgstr ""
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Filtros de archivo"
msgid "W&ord break characters:"
msgstr "Ordbrytningstecken:"
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Filfilter"
msgid "W&ord break characters:"
msgstr "&Sözcük Kesme Karakterleri:"
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Dosya Süzgeçleri"
msgid "W&ord break characters:"
msgstr "Символи, якимми розбиваються слова"
+msgid "&Rendering Mode:"
+msgstr ""
+
#, c-format
msgid "Filefilters"
msgstr "Фільтри файлів"