From: Takashi Sawanaka Date: Sun, 24 Nov 2019 22:43:43 +0000 (+0900) Subject: Add support for Color Emoji (WIP) X-Git-Tag: 2.16.5~16 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=2dd3f9d831e274d68a0f688b41d67afb092e2095;p=winmerge-jp%2Fwinmerge-jp.git Add support for Color Emoji (WIP) Add support for Color Emoji (WIP) --- diff --git a/Externals/crystaledit/Sample/SampleStatic.vs2017.vcxproj b/Externals/crystaledit/Sample/SampleStatic.vs2017.vcxproj index 00c41abf7..db0d82395 100644 --- a/Externals/crystaledit/Sample/SampleStatic.vs2017.vcxproj +++ b/Externals/crystaledit/Sample/SampleStatic.vs2017.vcxproj @@ -471,6 +471,8 @@ + + @@ -571,6 +573,9 @@ + + + diff --git a/Externals/crystaledit/Sample/SampleStatic.vs2017.vcxproj.filters b/Externals/crystaledit/Sample/SampleStatic.vs2017.vcxproj.filters index ca2a71229..803668f85 100644 --- a/Externals/crystaledit/Sample/SampleStatic.vs2017.vcxproj.filters +++ b/Externals/crystaledit/Sample/SampleStatic.vs2017.vcxproj.filters @@ -237,6 +237,12 @@ editlib + + editlib + + + editlib + @@ -361,6 +367,15 @@ editlib + + editlib + + + editlib + + + editlib + diff --git a/Externals/crystaledit/Sample/SampleStatic.vs2019.vcxproj b/Externals/crystaledit/Sample/SampleStatic.vs2019.vcxproj index 554bc792e..7a91d6720 100644 --- a/Externals/crystaledit/Sample/SampleStatic.vs2019.vcxproj +++ b/Externals/crystaledit/Sample/SampleStatic.vs2019.vcxproj @@ -471,6 +471,8 @@ + + @@ -571,6 +573,9 @@ + + + diff --git a/Externals/crystaledit/Sample/SampleStatic.vs2019.vcxproj.filters b/Externals/crystaledit/Sample/SampleStatic.vs2019.vcxproj.filters index e9e35d2f6..05af21309 100644 --- a/Externals/crystaledit/Sample/SampleStatic.vs2019.vcxproj.filters +++ b/Externals/crystaledit/Sample/SampleStatic.vs2019.vcxproj.filters @@ -237,6 +237,12 @@ editlib + + editlib + + + editlib + @@ -361,6 +367,15 @@ editlib + + editlib + + + editlib + + + editlib + diff --git a/Externals/crystaledit/editlib/ccrystalrenderer.h b/Externals/crystaledit/editlib/ccrystalrenderer.h new file mode 100644 index 000000000..7f4c00d5f --- /dev/null +++ b/Externals/crystaledit/editlib/ccrystalrenderer.h @@ -0,0 +1,46 @@ +/** + * @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; +}; + diff --git a/Externals/crystaledit/editlib/ccrystalrendererdirectwrite.cpp b/Externals/crystaledit/editlib/ccrystalrendererdirectwrite.cpp new file mode 100644 index 000000000..e631ba0c5 --- /dev/null +++ b/Externals/crystaledit/editlib/ccrystalrendererdirectwrite.cpp @@ -0,0 +1,616 @@ +/** + * @file ccrystalrendererdirectdraw.cpp + * + * @brief Implementation of the CCrystalRendererDirectWrite class + */ + +#ifdef _WIN64 +#undef WINVER +#define WINVER 0x0a00 +#include +#include "ccrystalrendererdirectwrite.h" +#include "resource.h" +#include +#include +#include +#include +#include + +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 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(glyphAdvances)[i] = static_cast(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(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(glyphRun.glyphAdvances)[i] = glyphRunOther.glyphAdvances[i]; + const_cast(glyphRun.glyphIndices)[i] = glyphRunOther.glyphIndices[i]; + if (glyphRunOther.glyphOffsets) + const_cast(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(glyphRun.glyphAdvances)[i] = other.glyphRun.glyphAdvances[i]; + const_cast(glyphRun.glyphIndices)[i] = other.glyphRun.glyphIndices[i]; + if (other.glyphRun.glyphOffsets) + const_cast(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 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(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(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(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 pTextRenderingParams, pTextRenderingParams2; + pWriteFactory->CreateRenderingParams(&pTextRenderingParams); + pWriteFactory->CreateCustomRenderingParams( + pTextRenderingParams->GetGamma(), + pTextRenderingParams->GetEnhancedContrast(), + 1.0f, + pTextRenderingParams->GetPixelGeometry(), + static_cast(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 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 pFontCollection; + pTextFormat->GetFontCollection(&pFontCollection); + if (pFontCollection) + { + CComPtr pFontFamily; + pFontCollection->GetFontFamily(0, &pFontFamily); + if (pFontFamily) + { + CComPtr 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(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(m_charSize.width), static_cast(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(left), static_cast(top), static_cast(right), static_cast(bottom)}, + static_cast(width), static_cast(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(IDR_MARGIN_ICONS_PNG), L"IMAGE")); + m_pIconBitmap->Create(&m_renderTarget); + } + auto size = m_pIconBitmap->GetPixelSize(); + CD2DRectF rcSrc{static_cast(iconIndex * MARGIN_ICON_WIDTH), 0.0f, static_cast((iconIndex + 1) * MARGIN_ICON_WIDTH), static_cast(MARGIN_ICON_HEIGHT)}; + m_renderTarget.DrawBitmap(m_pIconBitmap.get(), + { static_cast(x), static_cast(y), + static_cast(x + MARGIN_ICON_WIDTH), static_cast(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(x) - m_charSize.width * len - 4, static_cast(y), + static_cast(x), static_cast(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(left), static_cast(y) }, + { static_cast(right), static_cast(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(left), static_cast(y) }, + { static_cast(right), static_cast(y) }, + m_pTempBrush.get(), static_cast(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 pTextLayout; + AfxGetD2DState()->GetWriteFactory()->CreateTextLayout(text, static_cast(len), + *m_pCurrentTextFormat, + rcF.right - rcF.left, rcF.bottom - rcF.top, &pTextLayout); + pTextLayout->Draw(&drawingContext, m_pTextRenderer->Get(), 0, 0); + + std::vector> 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& a, const std::pair& b) + { return a.second < b.second; }); + float fBaselineOriginX = static_cast(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 pWriteFactory4(pWriteFactory); + CComQIPtr pD2dDeviceContext(m_renderTarget); + CComPtr glyphRunEnumerator; + + DWRITE_GLYPH_IMAGE_FORMATS supportedFormats = static_cast( + static_cast(DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE) | + static_cast(DWRITE_GLYPH_IMAGE_FORMATS_CFF) | + static_cast(DWRITE_GLYPH_IMAGE_FORMATS_COLR) | + static_cast(DWRITE_GLYPH_IMAGE_FORMATS_SVG) | + static_cast(DWRITE_GLYPH_IMAGE_FORMATS_PNG) | + static_cast(DWRITE_GLYPH_IMAGE_FORMATS_JPEG)| + static_cast(DWRITE_GLYPH_IMAGE_FORMATS_TIFF) | + static_cast(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 diff --git a/Externals/crystaledit/editlib/ccrystalrendererdirectwrite.h b/Externals/crystaledit/editlib/ccrystalrendererdirectwrite.h new file mode 100644 index 000000000..b1e7e9c3e --- /dev/null +++ b/Externals/crystaledit/editlib/ccrystalrendererdirectwrite.h @@ -0,0 +1,69 @@ +/** + * @file ccrystalrendererdirectdraw.h + * + * @brief Declaration file for CCrystalRendererDirectWrite + */ +#include "ccrystalrenderer.h" +#include +#include +#include + +#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, 4> m_pTextFormat; + CD2DTextFormat *m_pCurrentTextFormat; + std::unique_ptr m_pTextBrush; + std::unique_ptr m_pTempBrush; + std::unique_ptr m_pBackgroundBrush; + std::unique_ptr m_pTextRenderer; + std::unique_ptr m_pIconBitmap; + LOGFONT m_lfBaseFont; + std::unique_ptr m_pFont; + D2D1_SIZE_F m_charSize; + float m_fontAscent; +}; diff --git a/Externals/crystaledit/editlib/ccrystalrenderergdi.cpp b/Externals/crystaledit/editlib/ccrystalrenderergdi.cpp new file mode 100644 index 000000000..7b6cb27d8 --- /dev/null +++ b/Externals/crystaledit/editlib/ccrystalrenderergdi.cpp @@ -0,0 +1,192 @@ +/** + * @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(&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(len), const_cast(nWidths)); +} + diff --git a/Externals/crystaledit/editlib/ccrystalrenderergdi.h b/Externals/crystaledit/editlib/ccrystalrenderergdi.h new file mode 100644 index 000000000..f3ee5f1a6 --- /dev/null +++ b/Externals/crystaledit/editlib/ccrystalrenderergdi.h @@ -0,0 +1,50 @@ +/** + * @file ccrystalrenderergdi.h + * + * @brief Declaration file for CCrystalRendererGDI + */ +#include "ccrystalrenderer.h" +#include + +#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, 4> m_apFonts; + static CImageList *s_pIcons; +}; diff --git a/Externals/crystaledit/editlib/ccrystaltextview.cpp b/Externals/crystaledit/editlib/ccrystaltextview.cpp index be9f38cfa..1de437891 100644 --- a/Externals/crystaledit/editlib/ccrystaltextview.cpp +++ b/Externals/crystaledit/editlib/ccrystaltextview.cpp @@ -108,6 +108,8 @@ #include "string_util.h" #include "wcwidth.h" #include "icu.hpp" +#include "ccrystalrendererdirectwrite.h" +#include "ccrystalrenderergdi.h" using std::vector; using CrystalLineParser::TEXTBLOCK; @@ -165,6 +167,7 @@ LOGFONT CCrystalTextView::m_LogFont; 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); @@ -535,8 +538,6 @@ CCrystalTextView::CCrystalTextView () , m_bRememberLastPos(false) , m_pColors(nullptr) , m_nLastLineIndexCalculatedSubLineIndex(-1) -, m_pIcons(nullptr) -, m_apFonts{} , m_hAccel(nullptr) , m_pTextBuffer(nullptr) , m_pCacheBitmap(nullptr) @@ -592,7 +593,17 @@ CCrystalTextView::CCrystalTextView () , 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 ); @@ -652,7 +663,6 @@ CCrystalTextView::~CCrystalTextView () ASSERT(m_pnActualLineLength != nullptr); delete m_pnActualLineLength; m_pnActualLineLength = nullptr; - delete m_pIcons; if (m_pMarkers != nullptr) m_pMarkers->DeleteView(this); } @@ -1059,8 +1069,9 @@ ExpandChars (LPCTSTR pszChars, int nOffset, int nCount, CString & line, int nAct * @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) @@ -1153,48 +1164,37 @@ DrawLineHelperImpl (CDC * pdc, CPoint & ptOrigin, const CRect & rcClip, 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(); } } @@ -1212,7 +1212,7 @@ DrawLineHelperImpl (CDC * pdc, CPoint & ptOrigin, const CRect & rcClip, } 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) @@ -1266,24 +1266,28 @@ DrawLineHelper (CDC * pdc, CPoint & ptOrigin, const CRect & rcClip, int nColorIn // 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); } } } @@ -1466,7 +1470,7 @@ void CCrystalTextView::InvalidateScreenRect(bool bInvalidateView) } } -void CCrystalTextView::DrawScreenLine( CDC *pdc, CPoint &ptOrigin, const CRect &rcClip, +void CCrystalTextView::DrawScreenLine( CPoint &ptOrigin, const CRect &rcClip, const std::vector& blocks, int &nActualItem, COLORREF crText, COLORREF crBkgnd, bool bDrawWhitespace, LPCTSTR pszChars, int nOffset, int nCount, int &nActualOffset, CPoint ptTextPos ) @@ -1505,14 +1509,14 @@ void CCrystalTextView::DrawScreenLine( CDC *pdc, CPoint &ptOrigin, const CRect & 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 )); @@ -1529,7 +1533,9 @@ void CCrystalTextView::DrawScreenLine( CDC *pdc, CPoint &ptOrigin, const CRect & 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; @@ -1547,14 +1553,14 @@ void CCrystalTextView::DrawScreenLine( CDC *pdc, CPoint &ptOrigin, const CRect & 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)); @@ -1571,7 +1577,9 @@ void CCrystalTextView::DrawScreenLine( CDC *pdc, CPoint &ptOrigin, const CRect & 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; } } @@ -1579,7 +1587,7 @@ void CCrystalTextView::DrawScreenLine( CDC *pdc, CPoint &ptOrigin, const CRect & 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); } @@ -1595,8 +1603,9 @@ void CCrystalTextView::DrawScreenLine( CDC *pdc, CPoint &ptOrigin, const CRect & 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; } } @@ -1604,8 +1613,10 @@ void CCrystalTextView::DrawScreenLine( CDC *pdc, CPoint &ptOrigin, const CRect & 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; @@ -1770,7 +1781,7 @@ CCrystalTextView::GetTextBlocks(int nLineIndex) } 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 ()); @@ -1778,7 +1789,7 @@ DrawSingleLine (CDC * pdc, const CRect & rc, int nLineIndex) if (nLineIndex == -1) { // Draw line beyond the text - pdc->FillSolidRect (rc, GetColor (COLORINDEX_WHITESPACE)); + m_pCrystalRenderer->FillSolidRectangle (rc, GetColor (COLORINDEX_WHITESPACE)); return; } @@ -1803,9 +1814,9 @@ DrawSingleLine (CDC * pdc, const CRect & rc, int nLineIndex) // 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 ) { @@ -1814,7 +1825,7 @@ DrawSingleLine (CDC * pdc, const CRect & rc, int nLineIndex) // 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 ) ); @@ -1825,7 +1836,7 @@ DrawSingleLine (CDC * pdc, const CRect & rc, int 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], @@ -1834,7 +1845,7 @@ DrawSingleLine (CDC * pdc, const CRect & rc, int nLineIndex) // 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], @@ -1842,7 +1853,7 @@ DrawSingleLine (CDC * pdc, const CRect & rc, int nLineIndex) } else DrawScreenLine( - pdc, origin, rc, + origin, rc, blocks, nActualItem, crText, crBkgnd, bDrawWhitespace, pszChars, 0, nLength, nActualOffset, CPoint(0, nLineIndex)); @@ -1853,7 +1864,7 @@ DrawSingleLine (CDC * pdc, const CRect & rc, int 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); } } @@ -2130,24 +2141,18 @@ GetLineFlags (int nLineIndex) const * @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 @@ -2166,10 +2171,10 @@ DrawMargin (CDC * pdc, const CRect & rect, int nLineIndex, int nLineNumber) } // 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; @@ -2203,20 +2208,10 @@ DrawMargin (CDC * pdc, const CRect & rect, int nLineIndex, int nLineNumber) } } } - 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 @@ -2226,38 +2221,13 @@ DrawMargin (CDC * pdc, const CRect & rect, int nLineIndex, int nLineNumber) 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) { @@ -2322,7 +2292,11 @@ OnDraw (CDC * pdc) 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; } @@ -2346,72 +2320,59 @@ OnDraw (CDC * pdc) } 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 (); } @@ -2430,19 +2391,6 @@ ResetView () 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(); @@ -2543,56 +2491,14 @@ SetTabSize (int nTabSize) } } -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:: @@ -3063,11 +2969,8 @@ void 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); @@ -3176,6 +3079,9 @@ OnPrint (CDC * pdc, CPrintInfo * pInfo) 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++) @@ -3185,16 +3091,18 @@ OnPrint (CDC * pdc, CPrintInfo * pInfo) 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); } @@ -3471,20 +3379,11 @@ GetScreenChars () 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; @@ -4557,10 +4456,8 @@ void CCrystalTextView:: UpdateCompositionWindowFont() /* IME */ { HIMC hIMC = ImmGetContext(m_hWnd); - LOGFONT logfont; - GetFont()->GetLogFont(&logfont); - ImmSetCompositionFont(hIMC, &logfont); + ImmSetCompositionFont(hIMC, &m_lfBaseFont); ImmReleaseContext(m_hWnd, hIMC); } @@ -4609,14 +4506,7 @@ SetFont (const LOGFONT & lf) 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(); @@ -6092,6 +5982,18 @@ OnToggleColumnSelection () 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 { @@ -6426,9 +6328,7 @@ int CCrystalTextView::GetCharCellCountUnicodeChar(const wchar_t *pch) 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++) { @@ -6442,7 +6342,6 @@ int CCrystalTextView::GetCharCellCountUnicodeChar(const wchar_t *pch) } } m_bChWidthsCalculated[ch / 256] = true; - pdc->SelectObject(pOldFont); } } if (m_iChDoubleWidthFlags[ch / 32] & (1 << (ch % 32))) diff --git a/Externals/crystaledit/editlib/ccrystaltextview.h b/Externals/crystaledit/editlib/ccrystaltextview.h index a391a3564..386550626 100644 --- a/Externals/crystaledit/editlib/ccrystaltextview.h +++ b/Externals/crystaledit/editlib/ccrystaltextview.h @@ -37,6 +37,7 @@ #include "cregexp.h" #include "crystalparser.h" #include "crystallineparser.h" +#include "ccrystalrenderer.h" #include "icu.hpp" //////////////////////////////////////////////////////////////////////////// @@ -143,7 +144,6 @@ protected: private: LOGFONT m_lfBaseFont; LOGFONT m_lfSavedBaseFont; - CFont *m_apFonts[4]; // Parsing stuff @@ -188,14 +188,26 @@ protected: 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 (); @@ -214,7 +226,6 @@ protected : bool m_bOverrideCaret; bool m_bSingle; - CImageList * m_pIcons; CCrystalTextBuffer *m_pTextBuffer; HACCEL m_hAccel; bool m_bVertScrollBarLocked, m_bHorzScrollBarLocked; @@ -383,7 +394,6 @@ protected : 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); @@ -465,12 +475,10 @@ protected: 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) { @@ -580,11 +588,15 @@ protected: //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& 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& blocks, + int &nActualItem, + COLORREF crText, + COLORREF crBkgnd, bool bDrawWhitespace, + LPCTSTR pszChars, + + int nOffset, + int nCount, int &nActualOffset, CPoint ptTextPos ); //END SW std::vector MergeTextBlocks(const std::vector& blocks1, const std::vector& blocks2) const; @@ -680,6 +692,11 @@ public : 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 ); @@ -708,9 +725,12 @@ public : 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 m_pCrystalRenderer; typedef enum { diff --git a/Src/GhostTextView.cpp b/Src/GhostTextView.cpp index 41d71460c..bbadde0d0 100644 --- a/Src/GhostTextView.cpp +++ b/Src/GhostTextView.cpp @@ -278,12 +278,12 @@ HGLOBAL CGhostTextView::PrepareDragData () * @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); } diff --git a/Src/GhostTextView.h b/Src/GhostTextView.h index 278b5d49c..b5b20921c 100644 --- a/Src/GhostTextView.h +++ b/Src/GhostTextView.h @@ -115,6 +115,6 @@ public: 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; }; diff --git a/Src/MainFrm.cpp b/Src/MainFrm.cpp index 99a0a3ff0..e5a0bb21d 100644 --- a/Src/MainFrm.cpp +++ b/Src/MainFrm.cpp @@ -816,6 +816,9 @@ void CMainFrame::OnOptions() String filterPath = GetOptionsMgr()->GetString(OPT_FILTER_USERPATH); theApp.m_pGlobalFileFilter->SetUserFilterPath(filterPath); + CCrystalTextView::RENDERING_MODE nRenderingMode = static_cast(GetOptionsMgr()->GetInt(OPT_RENDERING_MODE)); + CCrystalTextView::SetRenderingModeDefault(nRenderingMode); + theApp.UpdateCodepageModule(); strdiff::SetBreakChars(GetOptionsMgr()->GetString(OPT_BREAK_SEPARATORS).c_str()); diff --git a/Src/Merge.cpp b/Src/Merge.cpp index d38f86b1b..f80b3cb7a 100644 --- a/Src/Merge.cpp +++ b/Src/Merge.cpp @@ -302,6 +302,8 @@ BOOL CMergeApp::InitInstance() if (m_pMarkers != nullptr) m_pMarkers->LoadFromRegistry(); + CCrystalTextView::SetRenderingModeDefault(static_cast(GetOptionsMgr()->GetInt(OPT_RENDERING_MODE))); + if (m_pLineFilters != nullptr) m_pLineFilters->Initialize(GetOptionsMgr()); diff --git a/Src/Merge.rc b/Src/Merge.rc index 6b89ba2ad..fdcc81f31 100644 --- a/Src/Merge.rc +++ b/Src/Merge.rc @@ -1342,6 +1342,8 @@ BEGIN COMBOBOX IDC_BREAK_TYPE,38,162,183,34,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP LTEXT "W&ord break characters:",IDC_STATIC,24,180,194,10 EDITTEXT IDC_BREAK_CHARS,24,192,198,14,ES_AUTOHSCROLL + LTEXT "&Rendering Mode:",IDC_STATIC,7,220,90,10 + COMBOBOX IDC_RENDERING_MODE,100,220,148,34,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP END IDD_MESSAGE_BOX DIALOGEX 0, 0, 186, 95 diff --git a/Src/Merge.vs2017.vcxproj b/Src/Merge.vs2017.vcxproj index 19d11d1c8..07912f3aa 100644 --- a/Src/Merge.vs2017.vcxproj +++ b/Src/Merge.vs2017.vcxproj @@ -31,7 +31,7 @@ {9FDA4AF0-CCFD-4812-BDB9-53EFEDB32BDE} Merge MFCProj - 10.0.17134.0 + 10.0.18362.0 @@ -45,7 +45,7 @@ Application Static Unicode - v141 + v141_xp false @@ -59,7 +59,7 @@ Application Static Unicode - v141_xp + v141 false @@ -73,7 +73,7 @@ Application Static Unicode - v141_xp + v141 false @@ -429,6 +429,10 @@ + + NotUsing + + @@ -1047,6 +1051,9 @@ + + + diff --git a/Src/Merge.vs2017.vcxproj.filters b/Src/Merge.vs2017.vcxproj.filters index 45bf2362e..6c0555427 100644 --- a/Src/Merge.vs2017.vcxproj.filters +++ b/Src/Merge.vs2017.vcxproj.filters @@ -874,6 +874,12 @@ EditLib\Source Files + + EditLib\Source Files + + + EditLib\Source Files + MFCGui\Dialogs\Source Files diff --git a/Src/Merge.vs2019.vcxproj b/Src/Merge.vs2019.vcxproj index 283514de6..dea827204 100644 --- a/Src/Merge.vs2019.vcxproj +++ b/Src/Merge.vs2019.vcxproj @@ -428,6 +428,15 @@ + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + @@ -1046,6 +1055,9 @@ + + + diff --git a/Src/Merge.vs2019.vcxproj.filters b/Src/Merge.vs2019.vcxproj.filters index 2d6f35988..56473a2eb 100644 --- a/Src/Merge.vs2019.vcxproj.filters +++ b/Src/Merge.vs2019.vcxproj.filters @@ -874,6 +874,12 @@ EditLib\Source Files + + EditLib\Source Files + + + EditLib\Source Files + MFCGui\Dialogs\Source Files diff --git a/Src/Merge2.rc b/Src/Merge2.rc index 283b2669e..b52eb49e3 100644 --- a/Src/Merge2.rc +++ b/Src/Merge2.rc @@ -104,6 +104,7 @@ END IDR_SPLASH IMAGE "res\\splash.jpg" IDR_LOGO IMAGE "res\\logo.jpg" +IDR_MARGIN_ICONS_PNG IMAGE "res\\mg_icons.png" ///////////////////////////////////////////////////////////////////////////// diff --git a/Src/MergeEditView.cpp b/Src/MergeEditView.cpp index 230b68dd9..2fcd2dab8 100644 --- a/Src/MergeEditView.cpp +++ b/Src/MergeEditView.cpp @@ -3047,6 +3047,9 @@ void CMergeEditView::OnUpdateShellMenu(CCmdUI* pCmdUI) */ void CMergeEditView::RefreshOptions() { + RENDERING_MODE nRenderingMode = static_cast(GetOptionsMgr()->GetInt(OPT_RENDERING_MODE)); + SetRenderingMode(nRenderingMode); + m_bAutomaticRescan = GetOptionsMgr()->GetBool(OPT_AUTOMATIC_RESCAN); if (GetOptionsMgr()->GetInt(OPT_TAB_TYPE) == 0) diff --git a/Src/OptionsDef.h b/Src/OptionsDef.h index ec7046ef9..22d9b8f6f 100644 --- a/Src/OptionsDef.h +++ b/Src/OptionsDef.h @@ -41,6 +41,7 @@ extern const String OPT_SYNTAX_HIGHLIGHT OP("Settings/HiliteSyntax"); 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"); diff --git a/Src/OptionsInit.cpp b/Src/OptionsInit.cpp index c44dc2c6d..5e60bd6fc 100644 --- a/Src/OptionsInit.cpp +++ b/Src/OptionsInit.cpp @@ -78,6 +78,7 @@ void Init(COptionsMgr *pOptions) 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(".,:;?[](){}<>`'!\"#$%&^~\\|@+-*/")); diff --git a/Src/PropEditor.cpp b/Src/PropEditor.cpp index c38c27949..054bcdf97 100644 --- a/Src/PropEditor.cpp +++ b/Src/PropEditor.cpp @@ -31,6 +31,7 @@ PropEditor::PropEditor(COptionsMgr *optionsMgr) , m_bViewLineDifferences(false) , m_bBreakOnWords(false) , m_nBreakType(0) +, m_nRenderingMode(0) { } @@ -51,6 +52,7 @@ void PropEditor::DoDataExchange(CDataExchange* pDX) 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 } @@ -78,6 +80,7 @@ void PropEditor::ReadOptions() 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; } /** @@ -99,6 +102,7 @@ void PropEditor::WriteOptions() 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); } /** @@ -108,7 +112,7 @@ BOOL PropEditor::OnInitDialog() { OptionsPanel::OnInitDialog(); - LoadBreakTypeStrings(); + LoadComboBoxStrings(); UpdateDataToWindow(); UpdateLineDiffControls(); @@ -119,11 +123,19 @@ BOOL PropEditor::OnInitDialog() /** * @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()); } /** diff --git a/Src/PropEditor.h b/Src/PropEditor.h index 27c504956..4a0723a3e 100644 --- a/Src/PropEditor.h +++ b/Src/PropEditor.h @@ -39,11 +39,12 @@ public: 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(); diff --git a/Src/res/mg_icons.png b/Src/res/mg_icons.png new file mode 100644 index 000000000..50405aefb Binary files /dev/null and b/Src/res/mg_icons.png differ diff --git a/Src/resource.h b/Src/resource.h index eef141cb8..3989077db 100644 --- a/Src/resource.h +++ b/Src/resource.h @@ -62,6 +62,7 @@ #define IDR_LOGO 307 #define IDR_SPLASH 308 #define IDB_WINMERGE 309 +#define IDR_MARGIN_ICONS_PNG 310 #define IDB_EDIT_COPY 316 #define IDB_EDIT_CUT 317 #define IDB_EDIT_PASTE 318 @@ -490,6 +491,7 @@ #define IDC_USE_DIR_COMPARE_COLORS 1364 #define IDC_PLUGIN_FILEFILTERS 1365 #define IDC_PLUGIN_FILEFILTERS_DEFAULTS 1366 +#define IDC_RENDERING_MODE 1367 #define IDC_DIFF_IGNORECP 1377 #define IDC_RESET 1378 #define IDC_LEFT1 1379 diff --git a/Translations/WinMerge/Basque.po b/Translations/WinMerge/Basque.po index 4105edeee..49cb3b3a4 100644 --- a/Translations/WinMerge/Basque.po +++ b/Translations/WinMerge/Basque.po @@ -1745,6 +1745,9 @@ msgstr "Hit&z maila:" msgid "W&ord break characters:" msgstr "" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Agiri-iragazkiak" diff --git a/Translations/WinMerge/Brazilian.po b/Translations/WinMerge/Brazilian.po index 70cbf1754..b33ac71b7 100644 --- a/Translations/WinMerge/Brazilian.po +++ b/Translations/WinMerge/Brazilian.po @@ -1745,6 +1745,9 @@ msgstr "&Nível das palavras:" msgid "W&ord break characters:" msgstr "C&aracters da quebra de linha:" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Filtros dos arquivos" diff --git a/Translations/WinMerge/Bulgarian.po b/Translations/WinMerge/Bulgarian.po index bdc970515..278cd531c 100644 --- a/Translations/WinMerge/Bulgarian.po +++ b/Translations/WinMerge/Bulgarian.po @@ -1346,6 +1346,9 @@ msgstr "На ниво &дума:" msgid "W&ord break characters:" msgstr "Символ за пренасяне на &дума:" +msgid "&Rendering Mode:" +msgstr "" + msgid "Filefilters" msgstr "Филтри за файлове" diff --git a/Translations/WinMerge/Catalan.po b/Translations/WinMerge/Catalan.po index cefc93140..e863d79f9 100644 --- a/Translations/WinMerge/Catalan.po +++ b/Translations/WinMerge/Catalan.po @@ -1741,6 +1741,9 @@ msgstr "Nivell de ¶ula:" msgid "W&ord break characters:" msgstr "" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Filtres de fitxer" diff --git a/Translations/WinMerge/ChineseSimplified.po b/Translations/WinMerge/ChineseSimplified.po index b99f6bba8..647771d6d 100644 --- a/Translations/WinMerge/ChineseSimplified.po +++ b/Translations/WinMerge/ChineseSimplified.po @@ -1744,6 +1744,9 @@ msgstr "单词级别(&W):" msgid "W&ord break characters:" msgstr "单词分隔字符:" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "文件过滤器" diff --git a/Translations/WinMerge/ChineseTraditional.po b/Translations/WinMerge/ChineseTraditional.po index f9301fb14..c67866b7e 100644 --- a/Translations/WinMerge/ChineseTraditional.po +++ b/Translations/WinMerge/ChineseTraditional.po @@ -1752,6 +1752,9 @@ msgstr "字階層(&W):" msgid "W&ord break characters:" msgstr "斷句字元(&O):" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "檔案篩選器" diff --git a/Translations/WinMerge/Croatian.po b/Translations/WinMerge/Croatian.po index f0f101650..0e31be148 100644 --- a/Translations/WinMerge/Croatian.po +++ b/Translations/WinMerge/Croatian.po @@ -1742,6 +1742,9 @@ msgstr "&Rijeć:" msgid "W&ord break characters:" msgstr "" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Filtar redaka" diff --git a/Translations/WinMerge/Czech.po b/Translations/WinMerge/Czech.po index ecbce21c9..b16f06549 100644 --- a/Translations/WinMerge/Czech.po +++ b/Translations/WinMerge/Czech.po @@ -1744,6 +1744,9 @@ msgstr "Na úrovni &slov:" msgid "W&ord break characters:" msgstr "Zn&aky oddělující slova:" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Filtrování souborů" diff --git a/Translations/WinMerge/Danish.po b/Translations/WinMerge/Danish.po index 5442ff22d..03dcfe53a 100644 --- a/Translations/WinMerge/Danish.po +++ b/Translations/WinMerge/Danish.po @@ -1747,6 +1747,9 @@ msgstr "&Ord niveau:" msgid "W&ord break characters:" msgstr "" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Filfiltre" diff --git a/Translations/WinMerge/Dutch.po b/Translations/WinMerge/Dutch.po index 6ef2dcd89..c3dcc3bad 100644 --- a/Translations/WinMerge/Dutch.po +++ b/Translations/WinMerge/Dutch.po @@ -1352,6 +1352,9 @@ msgstr "Woordniveau:" msgid "W&ord break characters:" msgstr "Woordsplitsingstekens:" +msgid "&Rendering Mode:" +msgstr "" + msgid "Filefilters" msgstr "Bestandsfilters" diff --git a/Translations/WinMerge/English.pot b/Translations/WinMerge/English.pot index aa3b568c2..9b71f41f2 100644 --- a/Translations/WinMerge/English.pot +++ b/Translations/WinMerge/English.pot @@ -1340,6 +1340,9 @@ msgstr "" msgid "W&ord break characters:" msgstr "" +msgid "&Rendering Mode:" +msgstr "" + msgid "Filefilters" msgstr "" diff --git a/Translations/WinMerge/Finnish.po b/Translations/WinMerge/Finnish.po index 3f586ba86..b14d6b7b7 100644 --- a/Translations/WinMerge/Finnish.po +++ b/Translations/WinMerge/Finnish.po @@ -1739,6 +1739,9 @@ msgstr "Sanataso:" msgid "W&ord break characters:" msgstr "" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Tiedostosuodattimet" diff --git a/Translations/WinMerge/French.po b/Translations/WinMerge/French.po index 902c7aa99..95d9d1f80 100644 --- a/Translations/WinMerge/French.po +++ b/Translations/WinMerge/French.po @@ -1753,6 +1753,9 @@ msgstr "Précision au &mot :" msgid "W&ord break characters:" msgstr "Caractères pour distinction de mot :" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Filtre des fichiers" diff --git a/Translations/WinMerge/Galician.po b/Translations/WinMerge/Galician.po index 91a877411..6590df9f0 100644 --- a/Translations/WinMerge/Galician.po +++ b/Translations/WinMerge/Galician.po @@ -1742,6 +1742,9 @@ msgstr "&A nivel da palabra:" msgid "W&ord break characters:" msgstr "" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Filtros de arquivos" diff --git a/Translations/WinMerge/German.po b/Translations/WinMerge/German.po index c3b8bac2f..66d54b625 100644 --- a/Translations/WinMerge/German.po +++ b/Translations/WinMerge/German.po @@ -1744,6 +1744,9 @@ msgstr "&Wort-Ebene:" msgid "W&ord break characters:" msgstr "W&ortumbruchzeichen:" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Dateifilter" diff --git a/Translations/WinMerge/Greek.po b/Translations/WinMerge/Greek.po index f7a633425..e5c4a57bd 100644 --- a/Translations/WinMerge/Greek.po +++ b/Translations/WinMerge/Greek.po @@ -1741,6 +1741,9 @@ msgstr "Επίπεδο &Λέξεων" msgid "W&ord break characters:" msgstr "" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Αρχειοφίλτρα" diff --git a/Translations/WinMerge/Hungarian.po b/Translations/WinMerge/Hungarian.po index 87c0904e4..656a85720 100644 --- a/Translations/WinMerge/Hungarian.po +++ b/Translations/WinMerge/Hungarian.po @@ -1742,6 +1742,9 @@ msgstr "" msgid "W&ord break characters:" msgstr "" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "FájlSzűrők" diff --git a/Translations/WinMerge/Italian.po b/Translations/WinMerge/Italian.po index 55db8f6f0..7bd110a66 100644 --- a/Translations/WinMerge/Italian.po +++ b/Translations/WinMerge/Italian.po @@ -1350,6 +1350,9 @@ msgstr "Livello &parole:" msgid "W&ord break characters:" msgstr "Caratteri terminatori &parola:" +msgid "&Rendering Mode:" +msgstr "" + msgid "Filefilters" msgstr "Filtri file" diff --git a/Translations/WinMerge/Japanese.po b/Translations/WinMerge/Japanese.po index da4ce52b0..5c0e18805 100644 --- a/Translations/WinMerge/Japanese.po +++ b/Translations/WinMerge/Japanese.po @@ -1355,6 +1355,9 @@ msgstr "単語単位(&W):" msgid "W&ord break characters:" msgstr "単語区切り文字(&O)" +msgid "&Rendering Mode:" +msgstr "レンダリングモード(&R):" + msgid "Filefilters" msgstr "ファイル フィルタ" diff --git a/Translations/WinMerge/Korean.po b/Translations/WinMerge/Korean.po index 8d968ab74..21ff0f116 100644 --- a/Translations/WinMerge/Korean.po +++ b/Translations/WinMerge/Korean.po @@ -1746,6 +1746,9 @@ msgstr "단어 단위(&W):" msgid "W&ord break characters:" msgstr "단어 분리 문자(&O):" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "파일 필터" diff --git a/Translations/WinMerge/Lithuanian.po b/Translations/WinMerge/Lithuanian.po index dd11ff0bd..4ed41db1f 100644 --- a/Translations/WinMerge/Lithuanian.po +++ b/Translations/WinMerge/Lithuanian.po @@ -1349,6 +1349,9 @@ msgstr "Žo&džio lygyje:" msgid "W&ord break characters:" msgstr "Ž&odžių skirtukų simboliai:" +msgid "&Rendering Mode:" +msgstr "" + msgid "Filefilters" msgstr "Failo filtrai" diff --git a/Translations/WinMerge/Norwegian.po b/Translations/WinMerge/Norwegian.po index ad34df2e5..0dab80b6e 100644 --- a/Translations/WinMerge/Norwegian.po +++ b/Translations/WinMerge/Norwegian.po @@ -1742,6 +1742,9 @@ msgstr "&Ord-nivÃ¥:" msgid "W&ord break characters:" msgstr "" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Filfiltere" diff --git a/Translations/WinMerge/Persian.po b/Translations/WinMerge/Persian.po index 15e8a66ad..4c1b24456 100644 --- a/Translations/WinMerge/Persian.po +++ b/Translations/WinMerge/Persian.po @@ -1749,6 +1749,9 @@ msgstr "&W در سطح کلمه : " msgid "W&ord break characters:" msgstr "" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr " پرونده صافيها " diff --git a/Translations/WinMerge/Polish.po b/Translations/WinMerge/Polish.po index 1635d41ba..1dcb78cda 100644 --- a/Translations/WinMerge/Polish.po +++ b/Translations/WinMerge/Polish.po @@ -1346,6 +1346,10 @@ msgstr "Poziom słów:" msgid "W&ord break characters:" msgstr "Znaki łamania wyrazów:" +msgid "&Rendering Mode:" +msgstr "" + +#, c-format msgid "Filefilters" msgstr "Filtry plików" diff --git a/Translations/WinMerge/Portuguese.po b/Translations/WinMerge/Portuguese.po index 4ff6d28e4..062e1ee5d 100644 --- a/Translations/WinMerge/Portuguese.po +++ b/Translations/WinMerge/Portuguese.po @@ -1744,6 +1744,9 @@ msgstr "A nível da palavra:" msgid "W&ord break characters:" msgstr "Caracteres da palavra:" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Filtros de ficheiro" diff --git a/Translations/WinMerge/Romanian.po b/Translations/WinMerge/Romanian.po index d96d19ae4..53d9fb79c 100644 --- a/Translations/WinMerge/Romanian.po +++ b/Translations/WinMerge/Romanian.po @@ -1742,6 +1742,9 @@ msgstr "La nivel de cu&vânt:" msgid "W&ord break characters:" msgstr "" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Filtre fişiere" diff --git a/Translations/WinMerge/Russian.po b/Translations/WinMerge/Russian.po index 87503e938..e38db328b 100644 --- a/Translations/WinMerge/Russian.po +++ b/Translations/WinMerge/Russian.po @@ -1744,6 +1744,9 @@ msgstr "По словам:" msgid "W&ord break characters:" msgstr "Символы разрыва слова:" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Фильтры файлов" diff --git a/Translations/WinMerge/Serbian.po b/Translations/WinMerge/Serbian.po index 97b9f4563..3d90ec519 100644 --- a/Translations/WinMerge/Serbian.po +++ b/Translations/WinMerge/Serbian.po @@ -1725,6 +1725,9 @@ msgstr "Ранг ре&чи:" msgid "W&ord break characters:" msgstr "" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Филтер датотека" diff --git a/Translations/WinMerge/Sinhala.po b/Translations/WinMerge/Sinhala.po index 5205c854d..80020e0e9 100644 --- a/Translations/WinMerge/Sinhala.po +++ b/Translations/WinMerge/Sinhala.po @@ -1739,6 +1739,9 @@ msgstr "& වචනයෙහි පිහිටුම" msgid "W&ord break characters:" msgstr "" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "ගොනුපෙරහන්" diff --git a/Translations/WinMerge/Slovak.po b/Translations/WinMerge/Slovak.po index f80f8b28d..b76070802 100644 --- a/Translations/WinMerge/Slovak.po +++ b/Translations/WinMerge/Slovak.po @@ -1742,6 +1742,9 @@ msgstr "Úroveň &slova:" msgid "W&ord break characters:" msgstr "Zalam&ovaÅ¥ slová:" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Filtre súborov" diff --git a/Translations/WinMerge/Slovenian.po b/Translations/WinMerge/Slovenian.po index 48b314f33..5264f5d96 100644 --- a/Translations/WinMerge/Slovenian.po +++ b/Translations/WinMerge/Slovenian.po @@ -1745,6 +1745,9 @@ msgstr "&besednem nivoju" msgid "W&ord break characters:" msgstr "&Znak za konec besede" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Datotečni filtri" diff --git a/Translations/WinMerge/Spanish.po b/Translations/WinMerge/Spanish.po index 34c660775..57252d015 100644 --- a/Translations/WinMerge/Spanish.po +++ b/Translations/WinMerge/Spanish.po @@ -1744,6 +1744,9 @@ msgstr "A nivel de &palabra:" msgid "W&ord break characters:" msgstr "" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Filtros de archivo" diff --git a/Translations/WinMerge/Swedish.po b/Translations/WinMerge/Swedish.po index fedea7a31..62b5b2ab3 100644 --- a/Translations/WinMerge/Swedish.po +++ b/Translations/WinMerge/Swedish.po @@ -1742,6 +1742,9 @@ msgstr "OrdnivÃ¥:" msgid "W&ord break characters:" msgstr "Ordbrytningstecken:" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Filfilter" diff --git a/Translations/WinMerge/Turkish.po b/Translations/WinMerge/Turkish.po index f464b63e3..4335d63fc 100644 --- a/Translations/WinMerge/Turkish.po +++ b/Translations/WinMerge/Turkish.po @@ -1745,6 +1745,9 @@ msgstr "&Sözcük Düzeyinde:" msgid "W&ord break characters:" msgstr "&Sözcük Kesme Karakterleri:" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Dosya Süzgeçleri" diff --git a/Translations/WinMerge/Ukrainian.po b/Translations/WinMerge/Ukrainian.po index bbd2126fd..41c0d98e7 100644 --- a/Translations/WinMerge/Ukrainian.po +++ b/Translations/WinMerge/Ukrainian.po @@ -1743,6 +1743,9 @@ msgstr "За словами:" msgid "W&ord break characters:" msgstr "Символи, якимми розбиваються слова" +msgid "&Rendering Mode:" +msgstr "" + #, c-format msgid "Filefilters" msgstr "Фільтри файлів"