diff --git a/scintilla/include/Scintilla.h b/scintilla/include/Scintilla.h index 69318f2aa..21e379570 100644 --- a/scintilla/include/Scintilla.h +++ b/scintilla/include/Scintilla.h @@ -19,16 +19,14 @@ extern "C" { // ============================================================== // --- needed to bind Scintilla as dynamic link library (DLL) --- // ============================================================== -typedef struct _dpi_t { unsigned x; unsigned y; } DPI_T; -typedef struct _wrct_t { long left; long top; long right; long bottom; } WRCT_T; -__declspec(dllexport) void Scintilla_LoadDpiForWindow(void); -__declspec(dllexport) int Scintilla_RegisterClasses(void *hInstance); -__declspec(dllexport) int Scintilla_ReleaseResources(void); -__declspec(dllexport) int Scintilla_InputCodePage(void); -__declspec(dllexport) DPI_T Scintilla_GetWindowDPI(void* hwnd); -__declspec(dllexport) int Scintilla_GetSystemMetricsForDpi(int nIndex, DPI_T dpi); -__declspec(dllexport) int Scintilla_GetSystemMetricsForDpi(int nIndex, DPI_T dpi); -__declspec(dllexport) int Scintilla_AdjustWindowRectForDpi(WRCT_T* lpRect, unsigned long dwStyle, unsigned long dwExStyle, DPI_T dpi); +typedef struct _wrct_t { long left; long top; long right; long bottom; } WRECT, *LPWRECT; // Windows RECT +__declspec(dllexport) int Scintilla_RegisterClasses(void *hInstance); +__declspec(dllexport) int Scintilla_ReleaseResources(void); +__declspec(dllexport) int Scintilla_InputCodePage(void); +__declspec(dllexport) unsigned Scintilla_GetWindowDPI(void* hwnd); +__declspec(dllexport) int Scintilla_GetSystemMetricsForDpi(int nIndex, unsigned dpi); +__declspec(dllexport) int Scintilla_GetSystemMetricsForDpi(int nIndex, unsigned dpi); +__declspec(dllexport) int Scintilla_AdjustWindowRectForDpi(LPWRECT lpRect, unsigned long dwStyle, unsigned long dwExStyle, unsigned dpi); // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< #ifdef __cplusplus diff --git a/scintilla/oniguruma/scintilla/OnigurumaRegExEngine.cxx b/scintilla/oniguruma/scintilla/OnigurumaRegExEngine.cxx index d7fe3be3b..c919d4a82 100644 --- a/scintilla/oniguruma/scintilla/OnigurumaRegExEngine.cxx +++ b/scintilla/oniguruma/scintilla/OnigurumaRegExEngine.cxx @@ -25,6 +25,7 @@ #define VC_EXTRALEAN 1 #include +#include "Geometry.h" #include "Platform.h" #include "Scintilla.h" #include "ILexer.h" diff --git a/scintilla/src/Document.cxx b/scintilla/src/Document.cxx index 5bb91ac3c..387adfad9 100644 --- a/scintilla/src/Document.cxx +++ b/scintilla/src/Document.cxx @@ -2368,10 +2368,10 @@ void Document::AnnotationSetText(Sci::Line line, const char *text) { void Document::AnnotationSetStyle(Sci::Line line, int style) { if (line >= 0 && line < LinesTotal()) { - Annotations()->SetStyle(line, style); - const DocModification mh(SC_MOD_CHANGEANNOTATION, LineStart(line), + Annotations()->SetStyle(line, style); + const DocModification mh(SC_MOD_CHANGEANNOTATION, LineStart(line), 0, 0, 0, line); - NotifyModified(mh); + NotifyModified(mh); } } @@ -2410,10 +2410,10 @@ void Document::EOLAnnotationSetText(Sci::Line line, const char *text) { void Document::EOLAnnotationSetStyle(Sci::Line line, int style) { if (line >= 0 && line < LinesTotal()) { - EOLAnnotations()->SetStyle(line, style); - const DocModification mh(SC_MOD_CHANGEEOLANNOTATION, LineStart(line), + EOLAnnotations()->SetStyle(line, style); + const DocModification mh(SC_MOD_CHANGEEOLANNOTATION, LineStart(line), 0, 0, 0, line); - NotifyModified(mh); + NotifyModified(mh); } } diff --git a/scintilla/src/Editor.cxx b/scintilla/src/Editor.cxx index 074d73b97..dc6eaa6ce 100644 --- a/scintilla/src/Editor.cxx +++ b/scintilla/src/Editor.cxx @@ -2169,9 +2169,7 @@ void Editor::CopyAllowLine() { void Editor::Cut() { pdoc->CheckReadOnly(); if (!pdoc->IsReadOnly() && !SelectionContainsProtected()) { - // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> - Copy(false); - // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< + Copy(); ClearSelection(); } } @@ -5205,7 +5203,7 @@ void Editor::QueueIdleWork(WorkItems items, Sci::Position upTo) { workNeeded.Need(items, upTo); } -int Editor::SupportsFeature(int feature) { +int Editor::SupportsFeature(int feature) const noexcept { AutoSurface surface(this); return surface->Supports(feature); } @@ -5721,30 +5719,24 @@ void Editor::StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam break; // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> case SCI_STYLESETBOLD: - vs.fontsValid = false; vs.styles[wParam].weight = lParam != 0 ? SC_WEIGHT_BOLD : SC_WEIGHT_NORMAL; break; case SCI_STYLESETWEIGHT: - vs.fontsValid = false; vs.styles[wParam].weight = static_cast(lParam); break; case SCI_STYLESETSTRETCH: - vs.fontsValid = false; vs.styles[wParam].stretch = static_cast(lParam); break; case SCI_STYLESETITALIC: - vs.fontsValid = false; vs.styles[wParam].italic = lParam != 0; break; case SCI_STYLESETEOLFILLED: vs.styles[wParam].eolFilled = lParam != 0; break; case SCI_STYLESETSIZE: - vs.fontsValid = false; vs.styles[wParam].size = static_cast(lParam * SC_FONT_SIZE_MULTIPLIER); break; case SCI_STYLESETSIZEFRACTIONAL: - vs.fontsValid = false; vs.styles[wParam].size = static_cast(lParam); break; case SCI_STYLESETFONT: @@ -5763,7 +5755,6 @@ void Editor::StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam vs.styles[wParam].caseForce = static_cast(lParam); break; case SCI_STYLESETCHARACTERSET: - vs.fontsValid = false; vs.styles[wParam].characterSet = static_cast(lParam); pdoc->SetCaseFolder(nullptr); break; @@ -5928,7 +5919,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { break; case SCI_COPY: - Copy(false); + Copy(); break; case SCI_COPYALLOWLINE: @@ -5956,7 +5947,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { break; case SCI_PASTE: - Paste(false); + Paste(); if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) { SetLastXChosen(); } @@ -6637,9 +6628,6 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_SETFONTQUALITY: vs.extraFontFlag &= ~SC_EFF_QUALITY_MASK; vs.extraFontFlag |= (wParam & SC_EFF_QUALITY_MASK); - // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> - vs.fontsValid = false; - // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< InvalidateStyleRedraw(); break; @@ -6873,7 +6861,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return caretSticky; case SCI_TOGGLECARETSTICKY: - caretSticky = !caretSticky; + caretSticky = caretSticky ? SC_CARETSTICKY_OFF : SC_CARETSTICKY_ON; break; case SCI_GETCOLUMN: @@ -6957,7 +6945,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return static_cast(imeIsInModeCJK); // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< - case SCI_SETBIDIRECTIONAL: + case SCI_SETBIDIRECTIONAL: // SCI_SETBIDIRECTIONAL is implemented on platform subclasses if they support bidirectional text. break; @@ -7805,7 +7793,6 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< if (zoomLevel != vs.zoomLevel) { vs.zoomLevel = zoomLevel; - vs.fontsValid = false; InvalidateStyleRedraw(); NotifyZoom(); } diff --git a/scintilla/src/Editor.h b/scintilla/src/Editor.h index ce540b407..d81443998 100644 --- a/scintilla/src/Editor.h +++ b/scintilla/src/Editor.h @@ -419,12 +419,10 @@ protected: // ScintillaBase subclass needs access to much of Editor void ClearDocumentStyle(); virtual void Cut(); void PasteRectangular(SelectionPosition pos, const char *ptr, Sci::Position len); -// >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> - virtual void Copy(bool asBinary) = 0; + virtual void Copy() = 0; virtual void CopyAllowLine(); virtual bool CanPaste(); - virtual void Paste(bool asBinary) = 0; -// <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< + virtual void Paste() = 0; void Clear(); virtual void SelectAll(); virtual void Undo(); @@ -549,7 +547,7 @@ protected: // ScintillaBase subclass needs access to much of Editor virtual int SupportsFeature(int feature) const noexcept; virtual bool PaintContains(PRectangle rc) const noexcept; - bool PaintContainsMargin(); + bool PaintContainsMargin() const noexcept; void CheckForChangeOutsidePaint(Range r); void SetBraceHighlight(Sci::Position pos0, Sci::Position pos1, int matchStyle); @@ -665,8 +663,7 @@ public: AutoSurface(SurfaceID sid, Editor *ed, int technology = -1, bool printing = false) { if (ed->wMain.GetID()) { surf = Surface::Allocate(technology != -1 ? technology : ed->technology); - //~surf->Init(sid, ed->wMain.GetID(), printing); - surf->Init(sid, ed->wMain.GetID()); + surf->Init(sid, ed->wMain.GetID()/* @@@, printing*/); surf->SetMode(SurfaceMode(ed->CodePage(), ed->BidirectionalR2L())); } } diff --git a/scintilla/src/Platform.h b/scintilla/src/Platform.h index 0480a1241..1517b3d04 100644 --- a/scintilla/src/Platform.h +++ b/scintilla/src/Platform.h @@ -6,6 +6,8 @@ // Copyright 1998-2009 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #pragma once +#ifndef PLATFORM_H +#define PLATFORM_H // PLAT_GTK = GTK+ on Linux or Win32 // PLAT_GTK_WIN32 is defined additionally when running PLAT_GTK under Win32 @@ -74,47 +76,15 @@ #endif -// use __vectorcall to pass float/double arguments such as Point and PRectangle. -#if defined(_WIN64) && defined(NDEBUG) - #if defined(_MSC_BUILD) - #define SCICALL __vectorcall - #elif defined(__INTEL_COMPILER_BUILD_DATE) - //#define SCICALL __regcall - #define SCICALL - #else - #define SCICALL - #endif -#else - #define SCICALL -#endif - - // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> -#include -#include -#include +#include +//#include +//#include +//#include // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< namespace Scintilla { -// official Scintilla use dynamic_cast, which requires RTTI. -#ifdef NDEBUG -#define USE_RTTI 0 -#else -#define USE_RTTI 1 -#endif - -template -inline DerivedPointer down_cast(Base* ptr) noexcept { -#if USE_RTTI - return dynamic_cast(ptr); -#else - return static_cast(ptr); -#endif -} - -typedef double XYACCUMULATOR; - // Underlying the implementation of the platform classes are platform specific types. // Sometimes these need to be passed around by client code so they are defined here @@ -125,8 +95,6 @@ typedef void *TickerID; typedef void *Function; typedef void *IdlerID; - -/** /** * Font management. */ @@ -198,7 +166,7 @@ public: class IScreenLineLayout { public: - virtual ~IScreenLineLayout() = default; + virtual ~IScreenLineLayout() noexcept = default; virtual size_t PositionFromX(XYPOSITION xDistance, bool charPosition) = 0; virtual XYPOSITION XFromPosition(size_t caretPosition) noexcept = 0; virtual std::vector FindRangeIntervals(size_t start, size_t end) = 0; @@ -244,45 +212,51 @@ public: virtual void Release() noexcept = 0; virtual int Supports(int feature) noexcept=0; - virtual bool Initialised() const noexcept = 0; - virtual void PenColour(ColourDesired fore) = 0; - virtual int LogPixelsY() const noexcept = 0; - virtual int DeviceHeightFont(int points) const noexcept = 0; - virtual void SCICALL MoveTo(int x_, int y_) noexcept = 0; - virtual void SCICALL LineTo(int x_, int y_) noexcept = 0; - virtual void SCICALL Polygon(const Point *pts, size_t npts, ColourDesired fore, ColourDesired back) = 0; - virtual void SCICALL RectangleDraw(PRectangle rc, ColourDesired fore, ColourDesired back) = 0; - virtual void SCICALL FillRectangle(PRectangle rc, ColourDesired back) = 0; - virtual void SCICALL FillRectangle(PRectangle rc, Surface &surfacePattern) = 0; - virtual void SCICALL RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back) = 0; - virtual void SCICALL AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill, - ColourDesired outline, int alphaOutline, int flags) = 0; - enum class GradientOptions { - leftToRight, topToBottom - }; - virtual void SCICALL GradientRectangle(PRectangle rc, const std::vector &stops, GradientOptions options) = 0; - virtual void SCICALL DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) = 0; - virtual void SCICALL Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back) = 0; - virtual void SCICALL Copy(PRectangle rc, Point from, Surface &surfaceSource) = 0; + virtual bool Initialised()=0; + virtual int LogPixelsY()=0; + virtual int PixelDivisions()=0; + virtual int DeviceHeightFont(int points)=0; + virtual void LineDraw(Point start, Point end, Stroke stroke)=0; + virtual void PolyLine(const Point *pts, size_t npts, Stroke stroke)=0; + virtual void Polygon(const Point *pts, size_t npts, FillStroke fillStroke)=0; + virtual void RectangleDraw(PRectangle rc, FillStroke fillStroke)=0; + virtual void RectangleFrame(PRectangle rc, Stroke stroke)=0; + virtual void FillRectangle(PRectangle rc, Fill fill)=0; + virtual void FillRectangleAligned(PRectangle rc, Fill fill)=0; + virtual void FillRectangle(PRectangle rc, Surface &surfacePattern)=0; + virtual void RoundedRectangle(PRectangle rc, FillStroke fillStroke)=0; + virtual void AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke)=0; + enum class GradientOptions { leftToRight, topToBottom }; + virtual void GradientRectangle(PRectangle rc, const std::vector &stops, GradientOptions options)=0; + virtual void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) = 0; + virtual void Ellipse(PRectangle rc, FillStroke fillStroke)=0; + virtual void Stadium(PRectangle rc, FillStroke fillStroke, Ends ends)=0; + virtual void Copy(PRectangle rc, Point from, Surface &surfaceSource)=0; virtual std::unique_ptr Layout(const IScreenLine *screenLine) = 0; - virtual void SCICALL DrawTextNoClip(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) = 0; - virtual void SCICALL DrawTextClipped(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) = 0; - virtual void SCICALL DrawTextTransparent(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, ColourDesired fore) = 0; - virtual void SCICALL MeasureWidths(const Font &font_, std::string_view text, XYPOSITION *positions) = 0; - virtual XYPOSITION WidthText(const Font &font_, std::string_view text) = 0; - virtual XYPOSITION Ascent(const Font &font_) noexcept = 0; - virtual XYPOSITION Descent(const Font &font_) noexcept = 0; - virtual XYPOSITION InternalLeading(const Font &font_) noexcept = 0; - virtual XYPOSITION Height(const Font &font_) noexcept = 0; - virtual XYPOSITION AverageCharWidth(const Font &font_) = 0; + virtual void DrawTextNoClip(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore, ColourAlpha back) = 0; + virtual void DrawTextClipped(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore, ColourAlpha back) = 0; + virtual void DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore) = 0; + virtual void MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) = 0; + virtual XYPOSITION WidthText(const Font *font_, std::string_view text) = 0; - virtual void SCICALL SetClip(PRectangle rc) noexcept = 0; + virtual void DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore, ColourAlpha back) = 0; + virtual void DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore, ColourAlpha back) = 0; + virtual void DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore) = 0; + virtual void MeasureWidthsUTF8(const Font *font_, std::string_view text, XYPOSITION *positions) = 0; + virtual XYPOSITION WidthTextUTF8(const Font *font_, std::string_view text) = 0; + + virtual XYPOSITION Ascent(const Font *font_)=0; + virtual XYPOSITION Descent(const Font *font_)=0; + virtual XYPOSITION InternalLeading(const Font *font_)=0; + virtual XYPOSITION Height(const Font *font_)=0; + virtual XYPOSITION AverageCharWidth(const Font *font_)=0; + + virtual void SetClip(PRectangle rc)=0; virtual void PopClip()=0; - virtual void FlushCachedState() noexcept = 0; + virtual void FlushCachedState()=0; virtual void FlushDrawing()=0; - }; /** @@ -292,9 +266,9 @@ public: class Window { protected: WindowID wid; - public: - Window() noexcept : wid(nullptr), cursorLast(Cursor::invalid) {} + Window() noexcept : wid(nullptr), cursorLast(Cursor::invalid) { + } Window(const Window &source) = delete; Window(Window &&) = delete; Window &operator=(WindowID wid_) noexcept { @@ -304,28 +278,20 @@ public: } Window &operator=(const Window &) = delete; Window &operator=(Window &&) = delete; - virtual ~Window(); - WindowID GetID() const noexcept { - return wid; - } - bool Created() const noexcept { - return wid != nullptr; - } + virtual ~Window() noexcept; + WindowID GetID() const noexcept { return wid; } + bool Created() const noexcept { return wid != nullptr; } void Destroy() noexcept; - PRectangle GetPosition() const noexcept; - void SCICALL SetPosition(PRectangle rc) noexcept; - void SCICALL SetPositionRelative(PRectangle rc, const Window *relativeTo) noexcept; - PRectangle GetClientPosition() const noexcept; - void Show(bool show = true) const noexcept; - void InvalidateAll() noexcept; - void SCICALL InvalidateRectangle(PRectangle rc) noexcept; - virtual void SetFont(const Font &font) noexcept; - enum class Cursor { - invalid, text, arrow, up, wait, horiz, vert, reverseArrow, hand - }; - void SetCursor(Cursor curs) noexcept; - PRectangle SCICALL GetMonitorRect(Point pt) const noexcept; - + PRectangle GetPosition() const; + void SetPosition(PRectangle rc); + void SetPositionRelative(PRectangle rc, const Window *relativeTo); + PRectangle GetClientPosition() const; + void Show(bool show=true); + void InvalidateAll(); + void InvalidateRectangle(PRectangle rc); + enum class Cursor { invalid, text, arrow, up, wait, horizontal, vertical, reverseArrow, hand }; + void SetCursor(Cursor curs); + PRectangle GetMonitorRect(Point pt); private: Cursor cursorLast; }; @@ -337,15 +303,14 @@ private: // ScintillaBase implements IListBoxDelegate to receive ListBoxEvents from a ListBox struct ListBoxEvent { - enum class EventType { - selectionChange, doubleClick - } event; - explicit ListBoxEvent(EventType event_) noexcept : event(event_) {} + enum class EventType { selectionChange, doubleClick } event; + ListBoxEvent(EventType event_) noexcept : event(event_) { + } }; class IListBoxDelegate { public: - virtual void ListNotify(ListBoxEvent *plbe) = 0; + virtual void ListNotify(ListBoxEvent *plbe)=0; }; struct ListOptions { @@ -358,29 +323,29 @@ struct ListOptions { class ListBox : public Window { public: ListBox() noexcept; - ~ListBox() override; - static ListBox *Allocate(); + virtual ~ListBox() noexcept override; + static std::unique_ptr Allocate(); - void SetFont(const Font &font) noexcept override = 0; - virtual void SetColour(ColourDesired fore, ColourDesired back) noexcept = 0; - virtual void SCICALL Create(Window &parent, int ctrlID, Point location, int lineHeight_, bool unicodeMode_, int technology_) noexcept = 0; - virtual void SetAverageCharWidth(int width) noexcept = 0; - virtual void SetVisibleRows(int rows) noexcept = 0; - virtual int GetVisibleRows() const noexcept = 0; - virtual PRectangle GetDesiredRect() = 0; - virtual int CaretFromEdge() const = 0; - virtual void Clear() noexcept = 0; - virtual void Append(const char *s, int type = -1) const noexcept = 0; - virtual int Length() const noexcept = 0; - virtual void Select(int n) = 0; - virtual int GetSelection() const noexcept = 0; - virtual int Find(const char *prefix) const noexcept = 0; - virtual void GetValue(int n, char *value, int len) const noexcept = 0; - virtual void RegisterImage(int type, const char *xpm_data) = 0; + virtual void SetFont(const Font *font)=0; + virtual void Create(Window &parent, int ctrlID, Point location, int lineHeight_, bool unicodeMode_, int technology_)=0; + virtual void SetAverageCharWidth(int width)=0; + virtual void SetVisibleRows(int rows)=0; + virtual int GetVisibleRows() const=0; + virtual PRectangle GetDesiredRect()=0; + virtual int CaretFromEdge()=0; + virtual void Clear() noexcept=0; + virtual void Append(char *s, int type = -1)=0; + virtual int Length()=0; + virtual void Select(int n)=0; + virtual int GetSelection()=0; + virtual int Find(const char *prefix)=0; + virtual std::string GetValue(int n)=0; + virtual void RegisterImage(int type, const char *xpm_data)=0; virtual void RegisterRGBAImage(int type, int width, int height, const unsigned char *pixelsImage) = 0; - virtual void ClearRegisteredImages() noexcept = 0; - virtual void SetDelegate(IListBoxDelegate *lbDelegate) noexcept = 0; - virtual void SetList(const char* list, char separator, char typesep) = 0; + virtual void ClearRegisteredImages()=0; + virtual void SetDelegate(IListBoxDelegate *lbDelegate)=0; + virtual void SetList(const char* list, char separator, char typesep)=0; + virtual void SetOptions(ListOptions options_)=0; }; /** @@ -390,39 +355,31 @@ class Menu { MenuID mid; public: Menu() noexcept; - MenuID GetID() const noexcept { - return mid; - } - void CreatePopUp() noexcept; + MenuID GetID() const noexcept { return mid; } + void CreatePopUp(); void Destroy() noexcept; - void SCICALL Show(Point pt, const Window &w) noexcept; + void Show(Point pt, const Window &w); }; /** - * Dynamic Library (DLL/SO/...) loading + * Platform namespace used to retrieve system wide parameters such as double click speed + * and chrome colour. */ -class DynamicLibrary { -public: - virtual ~DynamicLibrary() = default; +namespace Platform { - /// @return Pointer to function "name", or NULL on failure. - virtual Function FindFunction(const char *name) = 0; - - /// @return true if the library was loaded successfully. - virtual bool IsValid() = 0; - - /// @return An instance of a DynamicLibrary subclass with "modulePath" loaded. - static DynamicLibrary *Load(const char *modulePath); -}; - -#if defined(__clang__) - #if __has_feature(attribute_analyzer_noreturn) - #define CLANG_ANALYZER_NORETURN __attribute__((analyzer_noreturn)) - #else - #define CLANG_ANALYZER_NORETURN - #endif -#else - #define CLANG_ANALYZER_NORETURN -#endif +ColourDesired Chrome(); +ColourDesired ChromeHighlight(); +const char *DefaultFont(); +int DefaultFontSize(); +unsigned int DoubleClickTime(); +constexpr long LongFromTwoShorts(short a,short b) noexcept { + return (a) | ((b) << 16); +} } + + + +} // namespace + +#endif diff --git a/scintilla/src/ScintillaBase.cxx b/scintilla/src/ScintillaBase.cxx index 765e483d8..57ddc67f7 100644 --- a/scintilla/src/ScintillaBase.cxx +++ b/scintilla/src/ScintillaBase.cxx @@ -305,9 +305,6 @@ void ScintillaBase::AutoCompleteStart(Sci::Position lenEntered, const char *list rcac.right = rcac.left + widthLB; rcac.bottom = static_cast(std::min(static_cast(rcac.top) + heightLB, static_cast(rcPopupBounds.bottom))); ac.lb->SetPositionRelative(rcac, &wMain); - // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> - ac.lb->SetColour(vs.styles[STYLE_DEFAULT].fore, vs.styles[STYLE_DEFAULT].back); - // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< ac.lb->SetFont(vs.styles[STYLE_DEFAULT].font.get()); const unsigned int aveCharWidth = static_cast(vs.styles[STYLE_DEFAULT].aveCharWidth); ac.lb->SetAverageCharWidth(aveCharWidth); @@ -514,13 +511,15 @@ void ScintillaBase::CallTipClick() { NotifyParent(scn); } + +// >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> +#if SCI_EnablePopupMenu + bool ScintillaBase::ShouldDisplayPopup(Point ptInWindowCoordinates) const { return (displayPopupMenu == SC_POPUP_ALL || (displayPopupMenu == SC_POPUP_TEXT && !PointInSelMargin(ptInWindowCoordinates))); } -// >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> -#if SCI_EnablePopupMenu void ScintillaBase::ContextMenu(Point pt) { if (displayPopupMenu) { const bool writable = !WndProc(SCI_GETREADONLY, 0, 0); @@ -537,9 +536,11 @@ void ScintillaBase::ContextMenu(Point pt) { popup.Show(pt, wMain); } } + #endif // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< + void ScintillaBase::CancelModes() { AutoCompleteCancel(); ct.CallTipCancel(); diff --git a/scintilla/src/ScintillaBase.h b/scintilla/src/ScintillaBase.h index d041a2ff0..f990f1c15 100644 --- a/scintilla/src/ScintillaBase.h +++ b/scintilla/src/ScintillaBase.h @@ -78,11 +78,10 @@ protected: void CallTipShow(Point pt, const char *defn); virtual void CreateCallTipWindow(PRectangle rc) = 0; - bool ShouldDisplayPopup(Point ptInWindowCoordinates) const; - // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> #if SCI_EnablePopupMenu virtual void AddToPopUp(const char *label, int cmd=0, bool enabled=true) = 0; + bool ShouldDisplayPopup(Point ptInWindowCoordinates) const; void ContextMenu(Point pt); #endif // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< diff --git a/scintilla/src/ViewStyle.cxx b/scintilla/src/ViewStyle.cxx index 4b31e6837..1f768d6db 100644 --- a/scintilla/src/ViewStyle.cxx +++ b/scintilla/src/ViewStyle.cxx @@ -286,39 +286,33 @@ void ViewStyle::Init(size_t stylesSize_) { } void ViewStyle::Refresh(Surface &surface, int tabInChars) { - if (!fontsValid) { - fontsValid = true; - fonts.clear(); - - // Apply the extra font flag which controls text drawing quality to each style. - for (Style &style : styles) { - style.extraFontFlag = extraFontFlag; - } - - // Create a FontRealised object for each unique font in the styles. - CreateAndAddFont(styles[STYLE_DEFAULT]); - for (const Style &style : styles) { - CreateAndAddFont(style); - } - - // Ask platform to allocate each unique font. - for (std::pair> &font : fonts) { - font.second->Realise(surface, zoomLevel, technology, font.first); - } - - // Set the platform font handle and measurements for each style. - for (Style &style : styles) { - FontRealised *fr = Find(style); - style.Copy(fr->font, *fr); - } - - aveCharWidth = styles[STYLE_DEFAULT].aveCharWidth; - spaceWidth = styles[STYLE_DEFAULT].spaceWidth; - } + fonts.clear(); selbar = Platform::Chrome(); selbarlight = Platform::ChromeHighlight(); + // Apply the extra font flag which controls text drawing quality to each style. + for (Style &style : styles) { + style.extraFontFlag = extraFontFlag; + } + + // Create a FontRealised object for each unique font in the styles. + CreateAndAddFont(styles[STYLE_DEFAULT]); + for (const Style &style : styles) { + CreateAndAddFont(style); + } + + // Ask platform to allocate each unique font. + for (std::pair> &font : fonts) { + font.second->Realise(surface, zoomLevel, technology, font.first); + } + + // Set the platform font handle and measurements for each style. + for (Style &style : styles) { + FontRealised *fr = Find(style); + style.Copy(fr->font, *fr); + } + indicatorsDynamic = std::any_of(indicators.cbegin(), indicators.cend(), [](const Indicator &indicator) noexcept { return indicator.IsDynamic(); }); @@ -362,9 +356,6 @@ void ViewStyle::ReleaseAllExtendedStyles() noexcept { } int ViewStyle::AllocateExtendedStyles(int numberStyles) { - // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> - fontsValid = false; - // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< const int startRange = nextExtendedStyle; nextExtendedStyle += numberStyles; EnsureStyle(nextExtendedStyle); @@ -381,9 +372,6 @@ void ViewStyle::EnsureStyle(size_t index) { } void ViewStyle::ResetDefaultStyle() { - // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> - fontsValid = false; - // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< styles[STYLE_DEFAULT].Clear(ColourDesired(0,0,0), ColourDesired(0xff,0xff,0xff), Platform::DefaultFontSize() * SC_FONT_SIZE_MULTIPLIER, fontNames.Save(Platform::DefaultFont()), @@ -392,9 +380,6 @@ void ViewStyle::ResetDefaultStyle() { } void ViewStyle::ClearStyles() { - // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> - fontsValid = false; - // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< // Reset all styles to be like the default style for (size_t i=0; i>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> - fontsValid = false; - // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< styles[styleIndex].fontName = fontNames.Save(name); } @@ -631,7 +613,6 @@ bool ViewStyle::ZoomIn() noexcept { level = std::min(level, SC_MAX_ZOOM_LEVEL); if (level != zoomLevel) { zoomLevel = level; - fontsValid = false; return true; } } @@ -650,7 +631,6 @@ bool ViewStyle::ZoomOut() noexcept { level = std::max(level, SC_MIN_ZOOM_LEVEL); if (level != zoomLevel) { zoomLevel = level; - fontsValid = false; return true; } } @@ -659,9 +639,6 @@ bool ViewStyle::ZoomOut() noexcept { // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< void ViewStyle::AllocStyles(size_t sizeNew) { - // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> - fontsValid = false; - // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< size_t i=styles.size(); styles.resize(sizeNew); if (styles.size() > STYLE_DEFAULT) { diff --git a/scintilla/src/ViewStyle.h b/scintilla/src/ViewStyle.h index b2598ce56..b549e4760 100644 --- a/scintilla/src/ViewStyle.h +++ b/scintilla/src/ViewStyle.h @@ -96,7 +96,6 @@ public: std::vector indicators; bool indicatorsDynamic; bool indicatorsSetFore; - bool fontsValid; int technology; int lineHeight; int lineOverlap; @@ -157,8 +156,8 @@ public: int eolAnnotationVisible; int eolAnnotationStyleOffset; bool braceHighlightIndicatorSet; - bool braceBadLightIndicatorSet; int braceHighlightIndicator; + bool braceBadLightIndicatorSet; int braceBadLightIndicator; int edgeState; EdgeProperties theEdge; diff --git a/scintilla/win32/HanjaDic.cxx b/scintilla/win32/HanjaDic.cxx index 3daf16681..6464ce31e 100644 --- a/scintilla/win32/HanjaDic.cxx +++ b/scintilla/win32/HanjaDic.cxx @@ -69,8 +69,8 @@ public: hr = CLSIDFromProgID(OLESTR("mshjdic.hanjadic"), &CLSID_HanjaDic); if (SUCCEEDED(hr)) { hr = CoCreateInstance(CLSID_HanjaDic, nullptr, - CLSCTX_INPROC_SERVER, IID_IHanjaDic, - (LPVOID *)& HJinterface); + CLSCTX_INPROC_SERVER, IID_IHanjaDic, + (LPVOID *)& HJinterface); if (SUCCEEDED(hr)) { hr = HJinterface->OpenMainDic(); } diff --git a/scintilla/win32/HanjaDic.h b/scintilla/win32/HanjaDic.h index bb818ebfa..c7b8e2c79 100644 --- a/scintilla/win32/HanjaDic.h +++ b/scintilla/win32/HanjaDic.h @@ -6,6 +6,8 @@ // Copyright 2015 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #pragma once +#ifndef HANJADIC_H +#define HANJADIC_H namespace Scintilla { @@ -16,3 +18,5 @@ int GetHangulOfHanja(wchar_t *inout) noexcept; } } + +#endif diff --git a/scintilla/win32/PlatWin.cxx b/scintilla/win32/PlatWin.cxx index fc9b25029..6e6f5cf5f 100644 --- a/scintilla/win32/PlatWin.cxx +++ b/scintilla/win32/PlatWin.cxx @@ -14,45 +14,44 @@ #include #include -#include #include #include #include +#include #include #include #include -//#include - -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x601 /*_WIN32_WINNT_WIN7*/ -#endif -#ifndef WINVER -#define WINVER 0x601 /*_WIN32_WINNT_WIN7*/ -#endif -#ifndef NTDDI_VERSION -#define NTDDI_VERSION 0x06010000 /*NTDDI_WIN7*/ -#endif - -#define VC_EXTRALEAN 1 -#define WIN32_LEAN_AND_MEAN 1 +#include // Want to use std::min and std::max so don't want Windows.h version of min and max #if !defined(NOMINMAX) #define NOMINMAX #endif +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 +#undef WINVER +#define WINVER 0x0500 #include #include #include #include -#include -#include +#if !defined(DISABLE_D2D) +#define USE_D2D 1 +#endif + +#if defined(USE_D2D) +#include +#include +#endif + +#include "Debugging.h" +#include "Geometry.h" #include "Platform.h" #include "Scintilla.h" #include "XPM.h" -//~#include "CharClassify.h" -//~#include "DBCS.h" #include "UniConversion.h" +#include "DBCS.h" #include "FontQuality.h" #include "PlatWin.h" @@ -62,99 +61,14 @@ #endif #ifndef LOAD_LIBRARY_SEARCH_SYSTEM32 -#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 +#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 #endif -#if _WIN32_WINNT < _WIN32_WINNT_WIN8 -extern DWORD kSystemLibraryLoadFlags; -#else -#define kSystemLibraryLoadFlags LOAD_LIBRARY_SEARCH_SYSTEM32 +// __uuidof is a Microsoft extension but makes COM code neater, so disable warning +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wlanguage-extension-token" #endif -extern "C" unsigned g_uSystemDPI = USER_DEFAULT_SCREEN_DPI; - -namespace { - -using GetDpiForWindowSig = UINT (WINAPI *)(HWND hwnd); -GetDpiForWindowSig fnGetDpiForWindow = nullptr; - -#ifndef DPI_ENUMS_DECLARED -#define MDT_EFFECTIVE_DPI 0 -#endif - -using GetDpiForMonitorSig = HRESULT (WINAPI *)(HMONITOR hmonitor, /*MONITOR_DPI_TYPE*/int dpiType, UINT *dpiX, UINT *dpiY); -HMODULE hShcoreDLL {}; -GetDpiForMonitorSig fnGetDpiForMonitor = nullptr; - -using GetSystemMetricsForDpiSig = int (WINAPI *)(int nIndex, UINT dpi); -GetSystemMetricsForDpiSig fnGetSystemMetricsForDpi = nullptr; - -using AdjustWindowRectExForDpiSig = BOOL (WINAPI *)(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi); -AdjustWindowRectExForDpiSig fnAdjustWindowRectExForDpi = nullptr; - -} - -void Scintilla_LoadDpiForWindow(void) { - using Scintilla::DLLFunction; - - HMODULE user32 = ::GetModuleHandleW(L"user32.dll"); - fnGetDpiForWindow = DLLFunction(user32, "GetDpiForWindow"); - fnGetSystemMetricsForDpi = DLLFunction(user32, "GetSystemMetricsForDpi"); - fnAdjustWindowRectExForDpi = DLLFunction(user32, "AdjustWindowRectExForDpi"); - - using GetDpiForSystemSig = UINT (WINAPI *)(void); - GetDpiForSystemSig fnGetDpiForSystem = DLLFunction(user32, "GetDpiForSystem"); - if (fnGetDpiForSystem) { - g_uSystemDPI = fnGetDpiForSystem(); - } else { - HDC hDC = ::GetDC({}); - g_uSystemDPI = ::GetDeviceCaps(hDC, LOGPIXELSY); - ::ReleaseDC({}, hDC); - } - - if (!fnGetDpiForWindow) { - hShcoreDLL = ::LoadLibraryExW(L"shcore.dll", {}, LOAD_LIBRARY_SEARCH_SYSTEM32); - if (hShcoreDLL) { - fnGetDpiForMonitor = DLLFunction(hShcoreDLL, "GetDpiForMonitor"); - } - } -} - -DPI_T GetWindowDPI(HWND hwnd) { - DPI_T _dpi; - _dpi.x = g_uSystemDPI; - _dpi.y = g_uSystemDPI; - if (hwnd) { - if (fnGetDpiForWindow) { - _dpi.y = fnGetDpiForWindow(hwnd); - _dpi.x = _dpi.y; - } - else if (fnGetDpiForMonitor) { - HMONITOR hMonitor = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); - if (FAILED(fnGetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &(_dpi.x), &(_dpi.y)))) { - _dpi.x = g_uSystemDPI; - _dpi.y = g_uSystemDPI; - } - } - } - return _dpi; -} - -int SystemMetricsForDpi(int nIndex, unsigned dpi) { - if (fnGetSystemMetricsForDpi) { - return fnGetSystemMetricsForDpi(nIndex, dpi); - } - int const value = ::GetSystemMetrics(nIndex); - return ((dpi == g_uSystemDPI) ? value : ::MulDiv(value, dpi, g_uSystemDPI)); -} - -BOOL AdjustWindowRectForDpi(LPRECT lpRect, DWORD dwStyle, DWORD dwExStyle, unsigned dpi) { - if (fnAdjustWindowRectExForDpi) { - return fnAdjustWindowRectExForDpi(lpRect, dwStyle, FALSE, dwExStyle, dpi); - } - return ::AdjustWindowRectEx(lpRect, dwStyle, FALSE, dwExStyle); -} - namespace Scintilla { UINT CodePageFromCharSet(DWORD characterSet, UINT documentCodePage) noexcept; @@ -164,73 +78,60 @@ IDWriteFactory *pIDWriteFactory = nullptr; ID2D1Factory *pD2DFactory = nullptr; IDWriteRenderingParams *defaultRenderingParams = nullptr; IDWriteRenderingParams *customClearTypeRenderingParams = nullptr; -IDWriteGdiInterop *gdiInterop = nullptr; D2D1_DRAW_TEXT_OPTIONS d2dDrawTextOptions = D2D1_DRAW_TEXT_OPTIONS_NONE; static HMODULE hDLLD2D {}; static HMODULE hDLLDWrite {}; -static BOOL CALLBACK LoadD2DOnce(PINIT_ONCE initOnce, PVOID parameter, PVOID *lpContext) noexcept -{ - UNREFERENCED_PARAMETER(initOnce); - UNREFERENCED_PARAMETER(parameter); - UNREFERENCED_PARAMETER(lpContext); - - // Availability of SetDefaultDllDirectories implies Windows 8+ or - // that KB2533623 has been installed so LoadLibraryEx can be called - // with LOAD_LIBRARY_SEARCH_SYSTEM32. - - using D2D1CreateFactorySig = HRESULT(WINAPI *)(D2D1_FACTORY_TYPE factoryType, REFIID riid, - CONST D2D1_FACTORY_OPTIONS *pFactoryOptions, IUnknown **factory); - using DWriteCreateFactorySig = HRESULT(WINAPI *)(DWRITE_FACTORY_TYPE factoryType, REFIID iid, - IUnknown **factory); - - hDLLD2D = ::LoadLibraryEx(L"d2d1.dll", {}, kSystemLibraryLoadFlags); - if (hDLLD2D) { - D2D1CreateFactorySig fnD2DCF = DLLFunction(hDLLD2D, "D2D1CreateFactory"); - if (fnD2DCF) { -#ifdef NDEBUG - // A single threaded factory as Scintilla always draw on the GUI thread - fnD2DCF(D2D1_FACTORY_TYPE_SINGLE_THREADED, - __uuidof(ID2D1Factory), - nullptr, - reinterpret_cast(&pD2DFactory)); -#else - D2D1_FACTORY_OPTIONS options = {}; - options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; - fnD2DCF(D2D1_FACTORY_TYPE_SINGLE_THREADED, - __uuidof(ID2D1Factory), - &options, - reinterpret_cast(&pD2DFactory)); -#endif +void LoadD2DOnce() noexcept { + DWORD loadLibraryFlags = 0; + HMODULE kernel32 = ::GetModuleHandleW(L"kernel32.dll"); + if (kernel32) { + if (::GetProcAddress(kernel32, "SetDefaultDllDirectories")) { + // Availability of SetDefaultDllDirectories implies Windows 8+ or + // that KB2533623 has been installed so LoadLibraryEx can be called + // with LOAD_LIBRARY_SEARCH_SYSTEM32. + loadLibraryFlags = LOAD_LIBRARY_SEARCH_SYSTEM32; } } - hDLLDWrite = ::LoadLibraryEx(L"dwrite.dll", {}, kSystemLibraryLoadFlags); - if (hDLLDWrite) { - DWriteCreateFactorySig fnDWCF = DLLFunction(hDLLDWrite, "DWriteCreateFactory"); - if (fnDWCF) { - const GUID IID_IDWriteFactory2 = // 0439fc60-ca44-4994-8dee-3a9af7b732ec - { 0x0439fc60, 0xca44, 0x4994, { 0x8d, 0xee, 0x3a, 0x9a, 0xf7, 0xb7, 0x32, 0xec } }; + typedef HRESULT (WINAPI *D2D1CFSig)(D2D1_FACTORY_TYPE factoryType, REFIID riid, + CONST D2D1_FACTORY_OPTIONS *pFactoryOptions, IUnknown **factory); + typedef HRESULT (WINAPI *DWriteCFSig)(DWRITE_FACTORY_TYPE factoryType, REFIID iid, + IUnknown **factory); - const HRESULT hr = fnDWCF(DWRITE_FACTORY_TYPE_SHARED, - IID_IDWriteFactory2, + hDLLD2D = ::LoadLibraryEx(TEXT("D2D1.DLL"), 0, loadLibraryFlags); + D2D1CFSig fnD2DCF = DLLFunction(hDLLD2D, "D2D1CreateFactory"); + if (fnD2DCF) { + // A single threaded factory as Scintilla always draw on the GUI thread + fnD2DCF(D2D1_FACTORY_TYPE_SINGLE_THREADED, + __uuidof(ID2D1Factory), + nullptr, + reinterpret_cast(&pD2DFactory)); + } + hDLLDWrite = ::LoadLibraryEx(TEXT("DWRITE.DLL"), 0, loadLibraryFlags); + DWriteCFSig fnDWCF = DLLFunction(hDLLDWrite, "DWriteCreateFactory"); + if (fnDWCF) { + const GUID IID_IDWriteFactory2 = // 0439fc60-ca44-4994-8dee-3a9af7b732ec + { 0x0439fc60, 0xca44, 0x4994, { 0x8d, 0xee, 0x3a, 0x9a, 0xf7, 0xb7, 0x32, 0xec } }; + + const HRESULT hr = fnDWCF(DWRITE_FACTORY_TYPE_SHARED, + IID_IDWriteFactory2, + reinterpret_cast(&pIDWriteFactory)); + if (SUCCEEDED(hr)) { + // D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT + d2dDrawTextOptions = static_cast(0x00000004); + } else { + fnDWCF(DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), reinterpret_cast(&pIDWriteFactory)); - if (SUCCEEDED(hr)) { - // D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT - d2dDrawTextOptions = static_cast(0x00000004); - } else { - fnDWCF(DWRITE_FACTORY_TYPE_SHARED, - __uuidof(IDWriteFactory), - reinterpret_cast(&pIDWriteFactory)); - } } } if (pIDWriteFactory) { - HRESULT hr = pIDWriteFactory->CreateRenderingParams(&defaultRenderingParams); + const HRESULT hr = pIDWriteFactory->CreateRenderingParams(&defaultRenderingParams); if (SUCCEEDED(hr)) { - unsigned int clearTypeContrast; + unsigned int clearTypeContrast = 0; if (::SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &clearTypeContrast, 0)) { FLOAT gamma; @@ -243,103 +144,91 @@ static BOOL CALLBACK LoadD2DOnce(PINIT_ONCE initOnce, PVOID parameter, PVOID *lp defaultRenderingParams->GetPixelGeometry(), defaultRenderingParams->GetRenderingMode(), &customClearTypeRenderingParams); } } - - hr = pIDWriteFactory->GetGdiInterop(&gdiInterop); - if (!SUCCEEDED(hr)) { - ReleaseUnknown(gdiInterop); - } } - return TRUE; } -bool LoadD2D() noexcept { - static INIT_ONCE once = INIT_ONCE_STATIC_INIT; - ::InitOnceExecuteOnce(&once, LoadD2DOnce, nullptr, nullptr); - return (pIDWriteFactory && pD2DFactory); +bool LoadD2D() { + static std::once_flag once; + std::call_once(once, LoadD2DOnce); + return pIDWriteFactory && pD2DFactory; } + #endif -struct FormatAndMetrics { - int technology; - LOGFONTW lf; - HFONT hfont; -#if defined(USE_D2D) - IDWriteTextFormat *pTextFormat; +#ifndef CLEARTYPE_QUALITY +#define CLEARTYPE_QUALITY 5 #endif - int extraFontFlag; - int characterSet; - FLOAT yAscent; - FLOAT yDescent; - FLOAT yInternalLeading; - FormatAndMetrics(const LOGFONTW &lf_, HFONT hfont_, int extraFontFlag_, int characterSet_) noexcept : - technology(SCWIN_TECH_GDI), lf(lf_), hfont(hfont_), -#if defined(USE_D2D) - pTextFormat(nullptr), -#endif - extraFontFlag(extraFontFlag_), characterSet(characterSet_), yAscent(2), yDescent(1), yInternalLeading(0) {} -#if defined(USE_D2D) - FormatAndMetrics(const LOGFONTW &lf_, IDWriteTextFormat *pTextFormat_, - int extraFontFlag_, - int characterSet_, - FLOAT yAscent_, - FLOAT yDescent_, - FLOAT yInternalLeading_) noexcept : - technology(SCWIN_TECH_DIRECTWRITE), - lf(lf_), - hfont{}, - pTextFormat(pTextFormat_), - extraFontFlag(extraFontFlag_), - characterSet(characterSet_), - yAscent(yAscent_), - yDescent(yDescent_), - yInternalLeading(yInternalLeading_) {} -#endif - FormatAndMetrics(const FormatAndMetrics &) = delete; - FormatAndMetrics(FormatAndMetrics &&) = delete; - FormatAndMetrics &operator=(const FormatAndMetrics &) = delete; - FormatAndMetrics &operator=(FormatAndMetrics &&) = delete; - ~FormatAndMetrics() { - if (hfont) - ::DeleteObject(hfont); -#if defined(USE_D2D) - ReleaseUnknown(pTextFormat); -#endif - extraFontFlag = 0; - characterSet = 0; - yAscent = 2; - yDescent = 1; - yInternalLeading = 0; - } - HFONT HFont() const noexcept; -}; +void *PointerFromWindow(HWND hWnd) noexcept { + return reinterpret_cast(::GetWindowLongPtr(hWnd, 0)); +} -HFONT FormatAndMetrics::HFont() const noexcept { - return ::CreateFontIndirectW(&lf); +void SetWindowPointer(HWND hWnd, void *ptr) noexcept { + ::SetWindowLongPtr(hWnd, 0, reinterpret_cast(ptr)); } namespace { +// system DPI, same for all monitor. +UINT uSystemDPI = USER_DEFAULT_SCREEN_DPI; + +using GetDpiForWindowSig = UINT(WINAPI *)(HWND hwnd); +GetDpiForWindowSig fnGetDpiForWindow = nullptr; + +HMODULE hDLLShcore {}; +using GetDpiForMonitorSig = HRESULT (WINAPI *)(HMONITOR hmonitor, /*MONITOR_DPI_TYPE*/int dpiType, UINT *dpiX, UINT *dpiY); +GetDpiForMonitorSig fnGetDpiForMonitor = nullptr; + +using GetSystemMetricsForDpiSig = int(WINAPI *)(int nIndex, UINT dpi); +GetSystemMetricsForDpiSig fnGetSystemMetricsForDpi = nullptr; + +using AdjustWindowRectExForDpiSig = BOOL(WINAPI *)(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi); +AdjustWindowRectExForDpiSig fnAdjustWindowRectExForDpi = nullptr; + +void LoadDpiForWindow() noexcept { + HMODULE user32 = ::GetModuleHandleW(L"user32.dll"); + fnGetDpiForWindow = DLLFunction(user32, "GetDpiForWindow"); + fnGetSystemMetricsForDpi = DLLFunction(user32, "GetSystemMetricsForDpi"); + fnAdjustWindowRectExForDpi = DLLFunction(user32, "AdjustWindowRectExForDpi"); + + using GetDpiForSystemSig = UINT(WINAPI *)(void); + GetDpiForSystemSig fnGetDpiForSystem = DLLFunction(user32, "GetDpiForSystem"); + if (fnGetDpiForSystem) { + uSystemDPI = fnGetDpiForSystem(); + } else { + HDC hdcMeasure = ::CreateCompatibleDC({}); + uSystemDPI = ::GetDeviceCaps(hdcMeasure, LOGPIXELSY); + ::DeleteDC(hdcMeasure); + } + + if (!fnGetDpiForWindow) { + hDLLShcore = ::LoadLibraryExW(L"shcore.dll", {}, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (hDLLShcore) { + fnGetDpiForMonitor = DLLFunction(hDLLShcore, "GetDpiForMonitor"); + } + } +} + HINSTANCE hinstPlatformRes {}; -inline FormatAndMetrics *FamFromFontID(void *fid) noexcept { - return static_cast(fid); -} +const int SupportsGDI[] = { + SC_SUPPORTS_PIXEL_MODIFICATION, +}; constexpr BYTE Win32MapFontQuality(int extraFontFlag) noexcept { switch (extraFontFlag & SC_EFF_QUALITY_MASK) { - case SC_EFF_QUALITY_NON_ANTIALIASED: - return NONANTIALIASED_QUALITY; + case SC_EFF_QUALITY_NON_ANTIALIASED: + return NONANTIALIASED_QUALITY; - case SC_EFF_QUALITY_ANTIALIASED: - return ANTIALIASED_QUALITY; + case SC_EFF_QUALITY_ANTIALIASED: + return ANTIALIASED_QUALITY; - case SC_EFF_QUALITY_LCD_OPTIMIZED: - return CLEARTYPE_QUALITY; + case SC_EFF_QUALITY_LCD_OPTIMIZED: + return CLEARTYPE_QUALITY; - default: - return SC_EFF_QUALITY_DEFAULT; + default: + return SC_EFF_QUALITY_DEFAULT; } } @@ -347,26 +236,30 @@ constexpr BYTE Win32MapFontQuality(int extraFontFlag) noexcept { constexpr D2D1_TEXT_ANTIALIAS_MODE DWriteMapFontQuality(int extraFontFlag) noexcept { switch (extraFontFlag & SC_EFF_QUALITY_MASK) { - case SC_EFF_QUALITY_NON_ANTIALIASED: - return D2D1_TEXT_ANTIALIAS_MODE_ALIASED; + case SC_EFF_QUALITY_NON_ANTIALIASED: + return D2D1_TEXT_ANTIALIAS_MODE_ALIASED; - case SC_EFF_QUALITY_ANTIALIASED: - return D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; + case SC_EFF_QUALITY_ANTIALIASED: + return D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; - case SC_EFF_QUALITY_LCD_OPTIMIZED: - return D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; + case SC_EFF_QUALITY_LCD_OPTIMIZED: + return D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; - default: - return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; + default: + return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; } } #endif -void SetLogFont(LOGFONTW &lf, const char *faceName, int characterSet, float size, int weight, int stretch, bool italic, int extraFontFlag) { +// Both GDI and DirectWrite can produce a HFONT for use in list boxes +struct FontWin : public Font { + virtual HFONT HFont() const noexcept = 0; +}; + +void SetLogFont(LOGFONTW &lf, const char *faceName, int characterSet, XYPOSITION size, int weight, bool italic, int extraFontFlag) { lf = LOGFONTW(); // The negative is to allow for leading - lf.lfHeight = -std::abs(std::lround(size)); - lf.lfWidth = 0; // std::abs(std::lround(size * stretch / DWRITE_FONT_STRETCH_NORMAL)); + lf.lfHeight = -(std::abs(std::lround(size))); lf.lfWeight = weight; lf.lfItalic = italic ? 1 : 0; lf.lfCharSet = static_cast(characterSet); @@ -374,80 +267,58 @@ void SetLogFont(LOGFONTW &lf, const char *faceName, int characterSet, float size UTF16FromUTF8(faceName, lf.lfFaceName, LF_FACESIZE); } -#if defined(USE_D2D) -bool GetDWriteFontProperties(const LOGFONTW &lf, std::wstring &wsFamily, - DWRITE_FONT_WEIGHT &weight, DWRITE_FONT_STYLE &style, DWRITE_FONT_STRETCH &stretch) { - bool success = false; - if (gdiInterop) { - IDWriteFont *font = nullptr; - HRESULT hr = gdiInterop->CreateFontFromLOGFONT(&lf, &font); - if (SUCCEEDED(hr)) { - weight = font->GetWeight(); - style = font->GetStyle(); - stretch = font->GetStretch(); - - IDWriteFontFamily *family = nullptr; - hr = font->GetFontFamily(&family); - if (SUCCEEDED(hr)) { - IDWriteLocalizedStrings *names = nullptr; - hr = family->GetFamilyNames(&names); - if (SUCCEEDED(hr)) { - UINT32 index = 0; - BOOL exists = false; - names->FindLocaleName(L"en-us", &index, &exists); - if (!exists) { - index = 0; - } - - UINT32 length = 0; - names->GetStringLength(index, &length); - - wsFamily.resize(length + 1); - names->GetString(index, wsFamily.data(), length + 1); - - success = wsFamily[0] != L'\0'; - } - ReleaseUnknown(names); - } - ReleaseUnknown(family); - } - ReleaseUnknown(font); +struct FontGDI : public FontWin { + HFONT hfont = {}; + FontGDI(const FontParameters &fp) { + LOGFONTW lf; + SetLogFont(lf, fp.faceName, fp.characterSet, fp.size, fp.weight, fp.italic, fp.extraFontFlag); + hfont = ::CreateFontIndirectW(&lf); } - return success; -} -#endif - -FontID CreateFontFromParameters(const FontParameters &fp) { - LOGFONTW lf; - SetLogFont(lf, fp.faceName, fp.characterSet, fp.size, fp.weight, fp.stretch, fp.italic, fp.extraFontFlag); - FontID fid = nullptr; - if (fp.technology == SCWIN_TECH_GDI) { - HFONT hfont = ::CreateFontIndirectW(&lf); - fid = new FormatAndMetrics(lf, hfont, fp.extraFontFlag, fp.characterSet); - } else { -#if defined(USE_D2D) - IDWriteTextFormat *pTextFormat = nullptr; - std::wstring wsFamily; - const FLOAT fHeight = fp.size; - DWRITE_FONT_WEIGHT weight = static_cast(fp.weight); - DWRITE_FONT_STYLE style = fp.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; - DWRITE_FONT_STRETCH stretch = static_cast(fp.stretch); - if (!GetDWriteFontProperties(lf, wsFamily, weight, style, stretch)) { - wsFamily = WStringFromUTF8(fp.faceName); + // Deleted so FontGDI objects can not be copied. + FontGDI(const FontGDI &) = delete; + FontGDI(FontGDI &&) = delete; + FontGDI &operator=(const FontGDI &) = delete; + FontGDI &operator=(FontGDI &&) = delete; + ~FontGDI() noexcept override { + if (hfont) + ::DeleteObject(hfont); + } + HFONT HFont() const noexcept override { + // Duplicating hfont + LOGFONTW lf = {}; + if (0 == ::GetObjectW(hfont, sizeof(lf), &lf)) { + return {}; } + return ::CreateFontIndirectW(&lf); + } +}; +#if defined(USE_D2D) +struct FontDirectWrite : public FontWin { + IDWriteTextFormat *pTextFormat = nullptr; + int extraFontFlag = SC_EFF_QUALITY_DEFAULT; + int characterSet = 0; + FLOAT yAscent = 2.0f; + FLOAT yDescent = 1.0f; + FLOAT yInternalLeading = 0.0f; + + FontDirectWrite(const FontParameters &fp) : + extraFontFlag(fp.extraFontFlag), + characterSet(fp.characterSet) { + const std::wstring wsFace = WStringFromUTF8(fp.faceName); const std::wstring wsLocale = WStringFromUTF8(fp.localeName); - HRESULT hr = pIDWriteFactory->CreateTextFormat(wsFamily.c_str(), nullptr, - weight, style, stretch, fHeight, wsLocale.c_str(), &pTextFormat); + const FLOAT fHeight = static_cast(fp.size); + const DWRITE_FONT_STYLE style = fp.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; + HRESULT hr = pIDWriteFactory->CreateTextFormat(wsFace.c_str(), nullptr, + static_cast(fp.weight), + style, + DWRITE_FONT_STRETCH_NORMAL, fHeight, wsLocale.c_str(), &pTextFormat); if (SUCCEEDED(hr)) { pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); - FLOAT yAscent = 1.0f; - FLOAT yDescent = 1.0f; - FLOAT yInternalLeading = 0.0f; IDWriteTextLayout *pTextLayout = nullptr; hr = pIDWriteFactory->CreateTextLayout(L"X", 1, pTextFormat, - 100.0f, 100.0f, &pTextLayout); + 100.0f, 100.0f, &pTextLayout); if (SUCCEEDED(hr) && pTextLayout) { constexpr int maxLines = 2; DWRITE_LINE_METRICS lineMetrics[maxLines]{}; @@ -466,30 +337,39 @@ FontID CreateFontFromParameters(const FontParameters &fp) { ReleaseUnknown(pTextLayout); pTextFormat->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_UNIFORM, lineMetrics[0].height, lineMetrics[0].baseline); } - fid = new FormatAndMetrics(lf, pTextFormat, fp.extraFontFlag, fp.characterSet, yAscent, yDescent, yInternalLeading); } -#endif } - return fid; -} + // Deleted so FontDirectWrite objects can not be copied. + FontDirectWrite(const FontDirectWrite &) = delete; + FontDirectWrite(FontDirectWrite &&) = delete; + FontDirectWrite &operator=(const FontDirectWrite &) = delete; + FontDirectWrite &operator=(FontDirectWrite &&) = delete; + ~FontDirectWrite() noexcept override { + ReleaseUnknown(pTextFormat); + } + HFONT HFont() const noexcept override { + LOGFONTW lf = {}; + const HRESULT hr = pTextFormat->GetFontFamilyName(lf.lfFaceName, LF_FACESIZE); + if (!SUCCEEDED(hr)) { + return {}; + } + lf.lfWeight = pTextFormat->GetFontWeight(); + lf.lfItalic = pTextFormat->GetFontStyle() == DWRITE_FONT_STYLE_ITALIC; + lf.lfHeight = -static_cast(pTextFormat->GetFontSize()); + return ::CreateFontIndirectW(&lf); + } +}; +#endif } -Font::Font() noexcept : fid{} { -} - -Font::~Font() = default; - -void Font::Create(const FontParameters &fp) { - Release(); - if (fp.faceName) - fid = CreateFontFromParameters(fp); -} - -void Font::Release() noexcept { - if (fid) - delete FamFromFontID(fid); - fid = nullptr; +std::shared_ptr Font::Allocate(const FontParameters &fp) { +#if defined(USE_D2D) + if (fp.technology != SCWIN_TECH_GDI) { + return std::make_shared(fp); + } +#endif + return std::make_shared(fp); } // Buffer to hold strings and string position arrays without always allocating on heap. @@ -499,7 +379,7 @@ template class VarBuffer { T bufferStandard[lengthStandard]; public: - T * buffer; + T *buffer; explicit VarBuffer(size_t length) : buffer(nullptr) { if (length > lengthStandard) { buffer = new T[length]; @@ -513,9 +393,9 @@ public: VarBuffer &operator=(const VarBuffer &) = delete; VarBuffer &operator=(VarBuffer &&) = delete; - ~VarBuffer() { + ~VarBuffer() noexcept { if (buffer != bufferStandard) { - delete[]buffer; + delete []buffer; buffer = nullptr; } } @@ -525,9 +405,9 @@ constexpr int stackBufferLength = 1000; class TextWide : public VarBuffer { public: int tlen; // Using int instead of size_t as most Win32 APIs take int. - TextWide(std::string_view text, bool unicodeMode, int codePage = 0) : + TextWide(std::string_view text, int codePage) : VarBuffer(text.length()) { - if (unicodeMode) { + if (codePage == SC_CP_UTF8) { tlen = static_cast(UTF16FromUTF8(text, buffer, text.length())); } else { // Support Asian string display in 9x English @@ -536,12 +416,44 @@ public: } } }; -using TextPositions = VarBuffer; +typedef VarBuffer TextPositions; -class SurfaceGDI final : public Surface { - bool unicodeMode = false; +UINT DpiForWindow(WindowID wid) noexcept { + if (fnGetDpiForWindow) { + return fnGetDpiForWindow(HwndFromWindowID(wid)); + } + if (fnGetDpiForMonitor) { + HMONITOR hMonitor = ::MonitorFromWindow(HwndFromWindowID(wid), MONITOR_DEFAULTTONEAREST); + UINT dpiX = 0; + UINT dpiY = 0; + if (fnGetDpiForMonitor(hMonitor, 0 /*MDT_EFFECTIVE_DPI*/, &dpiX, &dpiY) == S_OK) { + return dpiY; + } + } + return uSystemDPI; +} + +int SystemMetricsForDpi(int nIndex, UINT dpi) noexcept { + if (fnGetSystemMetricsForDpi) { + return fnGetSystemMetricsForDpi(nIndex, dpi); + } + + int value = ::GetSystemMetrics(nIndex); + value = (dpi == uSystemDPI) ? value : ::MulDiv(value, dpi, uSystemDPI); + return value; +} + +BOOL AdjustWindowRectForDpi(LPRECT lpRect, DWORD dwStyle, DWORD dwExStyle, UINT dpi) noexcept { + if (fnAdjustWindowRectExForDpi) { + return fnAdjustWindowRectExForDpi(lpRect, dwStyle, FALSE, dwExStyle, dpi); + } + return ::AdjustWindowRectEx(lpRect, dwStyle, FALSE, dwExStyle); +} + +class SurfaceGDI : public Surface { + SurfaceMode mode; HDC hdc{}; - bool hdcOwned = false; + bool hdcOwned=false; HPEN pen{}; HPEN penOld{}; HBRUSH brush{}; @@ -556,14 +468,15 @@ class SurfaceGDI final : public Surface { // There appears to be a 16 bit string length limit in GDI on NT. int maxLenText = 65535; - int codePage = 0; + void PenColour(ColourAlpha fore, XYPOSITION widthStroke) noexcept; - void BrushColour(ColourDesired back) noexcept; - void SetFont(const Font &font_) noexcept; + void BrushColour(ColourAlpha back) noexcept; + void SetFont(const Font *font_) noexcept; void Clear() noexcept; public: - SurfaceGDI() noexcept = default; + SurfaceGDI() noexcept; + SurfaceGDI(HDC hdcCompatible, int width, int height, SurfaceMode mode_, int logPixelsY_) noexcept; // Deleted so SurfaceGDI objects can not be copied. SurfaceGDI(const SurfaceGDI &) = delete; SurfaceGDI(SurfaceGDI &&) = delete; @@ -572,51 +485,75 @@ public: ~SurfaceGDI() noexcept override; - void Init(WindowID wid) noexcept override; - void Init(SurfaceID sid, WindowID wid, bool printing = false) noexcept override; - void InitPixMap(int width, int height, Surface *surface_, WindowID wid) noexcept override; + void Init(WindowID wid) override; + void Init(SurfaceID sid, WindowID wid) override; + std::unique_ptr AllocatePixMap(int width, int height) override; + + void SetMode(SurfaceMode mode_) override; void Release() noexcept override; - bool Initialised() const noexcept override; - void PenColour(ColourDesired fore) noexcept override; - int LogPixelsY() const noexcept override; - int DeviceHeightFont(int points) const noexcept override; - void SCICALL MoveTo(int x_, int y_) noexcept override; - void SCICALL LineTo(int x_, int y_) noexcept override; - void SCICALL Polygon(const Point *pts, size_t npts, ColourDesired fore, ColourDesired back) override; - void SCICALL RectangleDraw(PRectangle rc, ColourDesired fore, ColourDesired back) noexcept override; - void SCICALL FillRectangle(PRectangle rc, ColourDesired back) noexcept override; - void SCICALL FillRectangle(PRectangle rc, Surface &surfacePattern) noexcept override; - void SCICALL RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back) noexcept override; - void SCICALL AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill, - ColourDesired outline, int alphaOutline, int flags) noexcept override; - void SCICALL GradientRectangle(PRectangle rc, const std::vector &stops, GradientOptions options) override; - void SCICALL DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) noexcept override; - void SCICALL Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back) noexcept override; - void SCICALL Copy(PRectangle rc, Point from, Surface &surfaceSource) noexcept override; + int Supports(int feature) noexcept override; + bool Initialised() override; + int LogPixelsY() override; + int PixelDivisions() override; + int DeviceHeightFont(int points) override; + void LineDraw(Point start, Point end, Stroke stroke) override; + void PolyLine(const Point *pts, size_t npts, Stroke stroke) override; + void Polygon(const Point *pts, size_t npts, FillStroke fillStroke) override; + void RectangleDraw(PRectangle rc, FillStroke fillStroke) override; + void RectangleFrame(PRectangle rc, Stroke stroke) override; + void FillRectangle(PRectangle rc, Fill fill) override; + void FillRectangleAligned(PRectangle rc, Fill fill) override; + void FillRectangle(PRectangle rc, Surface &surfacePattern) override; + void RoundedRectangle(PRectangle rc, FillStroke fillStroke) override; + void AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) override; + void GradientRectangle(PRectangle rc, const std::vector &stops, GradientOptions options) override; + void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) override; + void Ellipse(PRectangle rc, FillStroke fillStroke) override; + void Stadium(PRectangle rc, FillStroke fillStroke, Ends ends) override; + void Copy(PRectangle rc, Point from, Surface &surfaceSource) override; - std::unique_ptr Layout(const IScreenLine *screenLine) noexcept override; + std::unique_ptr Layout(const IScreenLine *screenLine) override; - void SCICALL DrawTextCommon(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, UINT fuOptions); - void SCICALL DrawTextNoClip(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) override; - void SCICALL DrawTextClipped(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) override; - void SCICALL DrawTextTransparent(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, ColourDesired fore) override; - void SCICALL MeasureWidths(const Font &font_, std::string_view text, XYPOSITION *positions) override; - XYPOSITION WidthText(const Font &font_, std::string_view text) override; - XYPOSITION Ascent(const Font &font_) noexcept override; - XYPOSITION Descent(const Font &font_) noexcept override; - XYPOSITION InternalLeading(const Font &font_) noexcept override; - XYPOSITION Height(const Font &font_) noexcept override; - XYPOSITION AverageCharWidth(const Font &font_) noexcept override; + void DrawTextCommon(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, UINT fuOptions); + void DrawTextNoClip(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore, ColourAlpha back) override; + void DrawTextClipped(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore, ColourAlpha back) override; + void DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore) override; + void MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) override; + XYPOSITION WidthText(const Font *font_, std::string_view text) override; - void SCICALL SetClip(PRectangle rc) noexcept override; - void FlushCachedState() noexcept override; + void DrawTextCommonUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, UINT fuOptions); + void DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore, ColourAlpha back) override; + void DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore, ColourAlpha back) override; + void DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore) override; + void MeasureWidthsUTF8(const Font *font_, std::string_view text, XYPOSITION *positions) override; + XYPOSITION WidthTextUTF8(const Font *font_, std::string_view text) override; - void SetUnicodeMode(bool unicodeMode_) noexcept override; - void SetDBCSMode(int codePage_) noexcept override; - void SetBidiR2L(bool bidiR2L_) noexcept override; + XYPOSITION Ascent(const Font *font_) override; + XYPOSITION Descent(const Font *font_) override; + XYPOSITION InternalLeading(const Font *font_) override; + XYPOSITION Height(const Font *font_) override; + XYPOSITION AverageCharWidth(const Font *font_) override; + + void SetClip(PRectangle rc) override; + void PopClip() override; + void FlushCachedState() override; + void FlushDrawing() override; }; +SurfaceGDI::SurfaceGDI() noexcept { +} + +SurfaceGDI::SurfaceGDI(HDC hdcCompatible, int width, int height, SurfaceMode mode_, int logPixelsY_) noexcept { + hdc = ::CreateCompatibleDC(hdc); + hdcOwned = true; + bitmap = ::CreateCompatibleBitmap(hdcCompatible, width, height); + bitmapOld = SelectBitmap(hdc, bitmap); + ::SetTextAlign(hdc, TA_BASELINE); + mode = mode_; + logPixelsY = logPixelsY_; +} + SurfaceGDI::~SurfaceGDI() noexcept { Clear(); } @@ -656,70 +593,79 @@ void SurfaceGDI::Release() noexcept { Clear(); } -bool SurfaceGDI::Initialised() const noexcept { - return hdc != nullptr; +int SurfaceGDI::Supports(int feature) noexcept { + for (const int f : SupportsGDI) { + if (f == feature) + return 1; + } + return 0; } -void SurfaceGDI::Init(WindowID wid) noexcept { +bool SurfaceGDI::Initialised() { + return hdc != 0; +} + +void SurfaceGDI::Init(WindowID wid) { Release(); - logPixelsY = DpiYForWindow(wid); hdc = ::CreateCompatibleDC({}); hdcOwned = true; ::SetTextAlign(hdc, TA_BASELINE); + logPixelsY = DpiForWindow(wid); } -void SurfaceGDI::Init(SurfaceID sid, WindowID wid, bool printing /*=false*/) noexcept { +void SurfaceGDI::Init(SurfaceID sid, WindowID wid) { Release(); hdc = static_cast(sid); - // Windows on screen are scaled but printers are not. - //const bool printing = (::GetDeviceCaps(hdc, TECHNOLOGY) != DT_RASDISPLAY); - logPixelsY = printing ? ::GetDeviceCaps(hdc, LOGPIXELSY) : DpiYForWindow(wid); - ::SetTextAlign(hdc, TA_BASELINE); -} - -void SurfaceGDI::InitPixMap(int width, int height, Surface *surface_, WindowID wid) noexcept { - Release(); - logPixelsY = DpiYForWindow(wid); - SurfaceGDI *psurfOther = down_cast(surface_); - // Should only ever be called with a SurfaceGDI, not a SurfaceD2D - PLATFORM_ASSERT(psurfOther); - hdc = ::CreateCompatibleDC(psurfOther->hdc); - hdcOwned = true; - bitmap = ::CreateCompatibleBitmap(psurfOther->hdc, width, height); - bitmapOld = SelectBitmap(hdc, bitmap); ::SetTextAlign(hdc, TA_BASELINE); - SetUnicodeMode(psurfOther->unicodeMode); - SetDBCSMode(psurfOther->codePage); + // Windows on screen are scaled but printers are not. + const bool printing = ::GetDeviceCaps(hdc, TECHNOLOGY) != DT_RASDISPLAY; + logPixelsY = printing ? ::GetDeviceCaps(hdc, LOGPIXELSY) : DpiForWindow(wid); } -void SurfaceGDI::PenColour(ColourDesired fore) noexcept { +std::unique_ptr SurfaceGDI::AllocatePixMap(int width, int height) { + return std::make_unique(hdc, width, height, mode, logPixelsY); +} + +void SurfaceGDI::SetMode(SurfaceMode mode_) { + mode = mode_; +} + +void SurfaceGDI::PenColour(ColourAlpha fore, XYPOSITION widthStroke) noexcept { if (pen) { ::SelectObject(hdc, penOld); ::DeleteObject(pen); pen = {}; penOld = {}; } - pen = ::CreatePen(PS_SOLID, 1, fore.AsInteger()); + const DWORD penWidth = std::lround(widthStroke); + const COLORREF penColour = fore.GetColour().AsInteger(); + if (widthStroke > 1) { + const LOGBRUSH brushParameters{ BS_SOLID, penColour, 0 }; + pen = ::ExtCreatePen(PS_GEOMETRIC | PS_ENDCAP_ROUND | PS_JOIN_MITER, + penWidth, + &brushParameters, + 0, + nullptr); + } else { + pen = ::CreatePen(PS_INSIDEFRAME, penWidth, penColour); + } penOld = SelectPen(hdc, pen); } -void SurfaceGDI::BrushColour(ColourDesired back) noexcept { +void SurfaceGDI::BrushColour(ColourAlpha back) noexcept { if (brush) { ::SelectObject(hdc, brushOld); ::DeleteObject(brush); brush = {}; brushOld = {}; } - // Only ever want pure, non-dithered brushes - //const ColourDesired colourNearest = ColourDesired(::GetNearestColor(hdc, back.AsInteger())); - //brush = ::CreateSolidBrush(colourNearest.AsInteger()); - brush = ::CreateSolidBrush(back.AsInteger()); + brush = ::CreateSolidBrush(back.GetColour().AsInteger()); brushOld = SelectBrush(hdc, brush); } -void SurfaceGDI::SetFont(const Font &font_) noexcept { - const FormatAndMetrics *pfm = FamFromFontID(font_.GetID()); - PLATFORM_ASSERT(pfm->technology == SCWIN_TECH_GDI); +void SurfaceGDI::SetFont(const Font *font_) noexcept { + const FontGDI *pfm = dynamic_cast(font_); + PLATFORM_ASSERT(pfm); if (fontOld) { SelectFont(hdc, pfm->hfont); } else { @@ -727,48 +673,74 @@ void SurfaceGDI::SetFont(const Font &font_) noexcept { } } -int SurfaceGDI::LogPixelsY() const noexcept { +int SurfaceGDI::LogPixelsY() { return logPixelsY; } -int SurfaceGDI::DeviceHeightFont(int points) const noexcept { - return ::MulDiv(points, logPixelsY, 72); +int SurfaceGDI::PixelDivisions() { + // Win32 uses device pixels. + return 1; } -void SurfaceGDI::MoveTo(int x_, int y_) noexcept { - ::MoveToEx(hdc, x_, y_, nullptr); +int SurfaceGDI::DeviceHeightFont(int points) { + return ::MulDiv(points, LogPixelsY(), 72); } -void SurfaceGDI::LineTo(int x_, int y_) noexcept { - ::LineTo(hdc, x_, y_); +void SurfaceGDI::LineDraw(Point start, Point end, Stroke stroke) { + PenColour(stroke.colour, stroke.width); + ::MoveToEx(hdc, std::lround(std::floor(start.x)), std::lround(std::floor(start.y)), nullptr); + ::LineTo(hdc, std::lround(std::floor(end.x)), std::lround(std::floor(end.y))); } -void SurfaceGDI::Polygon(const Point *pts, size_t npts, ColourDesired fore, ColourDesired back) { - PenColour(fore); - BrushColour(back); +void SurfaceGDI::PolyLine(const Point *pts, size_t npts, Stroke stroke) { + PLATFORM_ASSERT(npts > 1); + if (npts <= 1) { + return; + } + PenColour(stroke.colour, stroke.width); + std::vector outline; + std::transform(pts, pts + npts, std::back_inserter(outline), POINTFromPoint); + ::Polyline(hdc, outline.data(), static_cast(npts)); +} + +void SurfaceGDI::Polygon(const Point *pts, size_t npts, FillStroke fillStroke) { + PenColour(fillStroke.stroke.colour.GetColour(), fillStroke.stroke.width); + BrushColour(fillStroke.fill.colour.GetColour()); std::vector outline; std::transform(pts, pts + npts, std::back_inserter(outline), POINTFromPoint); ::Polygon(hdc, outline.data(), static_cast(npts)); } -void SurfaceGDI::RectangleDraw(PRectangle rc, ColourDesired fore, ColourDesired back) noexcept { - PenColour(fore); - BrushColour(back); - const RECT rcw = RectFromPRectangle(rc); - ::Rectangle(hdc, rcw.left, rcw.top, rcw.right, rcw.bottom); +void SurfaceGDI::RectangleDraw(PRectangle rc, FillStroke fillStroke) { + RectangleFrame(rc, fillStroke.stroke); + FillRectangle(rc.Inset(fillStroke.stroke.width), fillStroke.fill.colour); } -void SurfaceGDI::FillRectangle(PRectangle rc, ColourDesired back) noexcept { - // Using ExtTextOut rather than a FillRect ensures that no dithering occurs. - // There is no need to allocate a brush either. +void SurfaceGDI::RectangleFrame(PRectangle rc, Stroke stroke) { + BrushColour(stroke.colour); const RECT rcw = RectFromPRectangle(rc); - ::SetBkColor(hdc, back.AsInteger()); - ::ExtTextOut(hdc, rcw.left, rcw.top, ETO_OPAQUE, &rcw, L"", 0, nullptr); + ::FrameRect(hdc, &rcw, brush); } -void SurfaceGDI::FillRectangle(PRectangle rc, Surface &surfacePattern) noexcept { +void SurfaceGDI::FillRectangle(PRectangle rc, Fill fill) { + if (fill.colour.IsOpaque()) { + // Using ExtTextOut rather than a FillRect ensures that no dithering occurs. + // There is no need to allocate a brush either. + const RECT rcw = RectFromPRectangle(rc); + ::SetBkColor(hdc, fill.colour.GetColour().AsInteger()); + ::ExtTextOut(hdc, rcw.left, rcw.top, ETO_OPAQUE, &rcw, TEXT(""), 0, nullptr); + } else { + AlphaRectangle(rc, 0, FillStroke(fill.colour)); + } +} + +void SurfaceGDI::FillRectangleAligned(PRectangle rc, Fill fill) { + FillRectangle(PixelAlign(rc, 1), fill); +} + +void SurfaceGDI::FillRectangle(PRectangle rc, Surface &surfacePattern) { HBRUSH br; - if (SurfaceGDI *psgdi = down_cast(&surfacePattern); psgdi && psgdi->bitmap) { + if (SurfaceGDI *psgdi = dynamic_cast(&surfacePattern); psgdi && psgdi->bitmap) { br = ::CreatePatternBrush(psgdi->bitmap); } else { // Something is wrong so display in red br = ::CreateSolidBrush(RGB(0xff, 0, 0)); @@ -778,9 +750,9 @@ void SurfaceGDI::FillRectangle(PRectangle rc, Surface &surfacePattern) noexcept ::DeleteObject(br); } -void SurfaceGDI::RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back) noexcept { - PenColour(fore); - BrushColour(back); +void SurfaceGDI::RoundedRectangle(PRectangle rc, FillStroke fillStroke) { + PenColour(fillStroke.stroke.colour, fillStroke.stroke.width); + BrushColour(fillStroke.fill.colour); const RECT rcw = RectFromPRectangle(rc); ::RoundRect(hdc, rcw.left + 1, rcw.top, @@ -798,19 +770,19 @@ constexpr byte AlphaScaled(unsigned char component, unsigned int alpha) noexcept return static_cast(component * alpha / 255); } -constexpr DWORD dwordMultiplied(ColourDesired colour, unsigned int alpha) noexcept { +constexpr DWORD dwordMultiplied(ColourAlpha colour) noexcept { return dwordFromBGRA( - AlphaScaled(colour.GetBlue(), alpha), - AlphaScaled(colour.GetGreen(), alpha), - AlphaScaled(colour.GetRed(), alpha), - static_cast(alpha)); + AlphaScaled(colour.GetBlue(), colour.GetAlpha()), + AlphaScaled(colour.GetGreen(), colour.GetAlpha()), + AlphaScaled(colour.GetRed(), colour.GetAlpha()), + colour.GetAlpha()); } class DIBSection { - HDC hMemDC{}; - HBITMAP hbmMem{}; - HBITMAP hbmOld{}; - SIZE size{}; + HDC hMemDC {}; + HBITMAP hbmMem {}; + HBITMAP hbmOld {}; + SIZE size {}; DWORD *pixels = nullptr; public: DIBSection(HDC hdc, SIZE size_) noexcept; @@ -887,11 +859,11 @@ void DIBSection::SetSymmetric(LONG x, LONG y, DWORD value) noexcept { SetPixel(xSymmetric, ySymmetric, value); } -constexpr unsigned int Proportional(unsigned char a, unsigned char b, float t) noexcept { +constexpr unsigned int Proportional(unsigned char a, unsigned char b, XYPOSITION t) noexcept { return static_cast(a + t * (b - a)); } -ColourAlpha Proportional(ColourAlpha a, ColourAlpha b, float t) noexcept { +ColourAlpha Proportional(ColourAlpha a, ColourAlpha b, XYPOSITION t) noexcept { return ColourAlpha( Proportional(a.GetRed(), b.GetRed(), t), Proportional(a.GetGreen(), b.GetGreen(), t), @@ -899,13 +871,13 @@ ColourAlpha Proportional(ColourAlpha a, ColourAlpha b, float t) noexcept { Proportional(a.GetAlpha(), b.GetAlpha(), t)); } -ColourAlpha GradientValue(const std::vector &stops, float proportion) noexcept { +ColourAlpha GradientValue(const std::vector &stops, XYPOSITION proportion) noexcept { for (size_t stop = 0; stop < stops.size() - 1; stop++) { // Loop through each pair of stops - const float positionStart = stops[stop].position; - const float positionEnd = stops[stop + 1].position; + const XYPOSITION positionStart = stops[stop].position; + const XYPOSITION positionEnd = stops[stop + 1].position; if ((proportion >= positionStart) && (proportion <= positionEnd)) { - const float proportionInPair = (proportion - positionStart) / + const XYPOSITION proportionInPair = (proportion - positionStart) / (positionEnd - positionStart); return Proportional(stops[stop].colour, stops[stop + 1].colour, proportionInPair); } @@ -922,25 +894,28 @@ constexpr BLENDFUNCTION mergeAlpha = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; } -void SurfaceGDI::AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill, - ColourDesired outline, int alphaOutline, int /* flags*/) noexcept { +void SurfaceGDI::AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) { + // TODO: Implement strokeWidth const RECT rcw = RectFromPRectangle(rc); const SIZE size = SizeOfRect(rcw); if (size.cx > 0) { - DIBSection section(hdc, size); - if (section) { - // Ensure not distorted too much by corners when small - const LONG corner = std::min(cornerSize, (std::min(size.cx, size.cy) / 2) - 2); - constexpr DWORD valEmpty = dwordFromBGRA(0, 0, 0, 0); - const DWORD valFill = dwordMultiplied(fill, alphaFill); - const DWORD valOutline = dwordMultiplied(outline, alphaOutline); + DIBSection section(hdc, size); + + if (section) { + + // Ensure not distorted too much by corners when small + const LONG corner = std::min(static_cast(cornerSize), (std::min(size.cx, size.cy) / 2) - 2); + + constexpr DWORD valEmpty = dwordFromBGRA(0,0,0,0); + const DWORD valFill = dwordMultiplied(fillStroke.fill.colour); + const DWORD valOutline = dwordMultiplied(fillStroke.stroke.colour); // Draw a framed rectangle - for (int y = 0; y < size.cy; y++) { - for (int x = 0; x < size.cx; x++) { - if ((x == 0) || (x == size.cx - 1) || (y == 0) || (y == size.cy - 1)) { + for (int y=0; y &stops, GradientOptions options) { + const RECT rcw = RectFromPRectangle(rc); const SIZE size = SizeOfRect(rcw); DIBSection section(hdc, size); + if (section) { + if (options == GradientOptions::topToBottom) { for (LONG y = 0; y < size.cy; y++) { // Find y/height proportional colour - const float proportion = y / (rc.Height() - 1.0f); + const XYPOSITION proportion = y / (rc.Height() - 1.0f); const ColourAlpha mixed = GradientValue(stops, proportion); - const DWORD valFill = dwordMultiplied(mixed, mixed.GetAlpha()); + const DWORD valFill = dwordMultiplied(mixed); for (LONG x = 0; x < size.cx; x++) { section.SetPixel(x, y, valFill); } @@ -987,20 +965,20 @@ void SurfaceGDI::GradientRectangle(PRectangle rc, const std::vector } else { for (LONG x = 0; x < size.cx; x++) { // Find x/width proportional colour - const float proportion = x / (rc.Width() - 1.0f); + const XYPOSITION proportion = x / (rc.Width() - 1.0f); const ColourAlpha mixed = GradientValue(stops, proportion); - const DWORD valFill = dwordMultiplied(mixed, mixed.GetAlpha()); + const DWORD valFill = dwordMultiplied(mixed); for (LONG y = 0; y < size.cy; y++) { section.SetPixel(x, y, valFill); } } } - GdiAlphaBlend(hdc, rcw.left, rcw.top, size.cx, size.cy, section.DC(), 0, 0, size.cx, size.cy, mergeAlpha); + AlphaBlend(hdc, rcw.left, rcw.top, size.cx, size.cy, section.DC(), 0, 0, size.cx, size.cy, mergeAlpha); } } -void SurfaceGDI::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) noexcept { +void SurfaceGDI::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) { if (rc.Width() > 0) { if (rc.Width() > width) rc.left += std::floor((rc.Width() - width) / 2); @@ -1009,25 +987,30 @@ void SurfaceGDI::DrawRGBAImage(PRectangle rc, int width, int height, const unsig rc.top += std::floor((rc.Height() - height) / 2); rc.bottom = rc.top + height; - const SIZE size{ width, height }; + const SIZE size { width, height }; DIBSection section(hdc, size); if (section) { RGBAImage::BGRAFromRGBA(section.Bytes(), pixelsImage, width * height); - GdiAlphaBlend(hdc, static_cast(rc.left), static_cast(rc.top), + AlphaBlend(hdc, static_cast(rc.left), static_cast(rc.top), static_cast(rc.Width()), static_cast(rc.Height()), section.DC(), 0, 0, width, height, mergeAlpha); } } } -void SurfaceGDI::Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back) noexcept { - PenColour(fore); - BrushColour(back); +void SurfaceGDI::Ellipse(PRectangle rc, FillStroke fillStroke) { + PenColour(fillStroke.stroke.colour, fillStroke.stroke.width); + BrushColour(fillStroke.fill.colour); const RECT rcw = RectFromPRectangle(rc); ::Ellipse(hdc, rcw.left, rcw.top, rcw.right, rcw.bottom); } -void SurfaceGDI::Copy(PRectangle rc, Point from, Surface &surfaceSource) noexcept { +void SurfaceGDI::Stadium(PRectangle rc, FillStroke fillStroke, [[maybe_unused]] Ends ends) { + // TODO: Implement properly - the rectangle is just a placeholder + RectangleDraw(rc, fillStroke); +} + +void SurfaceGDI::Copy(PRectangle rc, Point from, Surface &surfaceSource) { ::BitBlt(hdc, static_cast(rc.left), static_cast(rc.top), static_cast(rc.Width()), static_cast(rc.Height()), @@ -1035,46 +1018,46 @@ void SurfaceGDI::Copy(PRectangle rc, Point from, Surface &surfaceSource) noexcep static_cast(from.x), static_cast(from.y), SRCCOPY); } -std::unique_ptr SurfaceGDI::Layout(const IScreenLine *) noexcept { +std::unique_ptr SurfaceGDI::Layout(const IScreenLine *) { return {}; } -using TextPositionsI = VarBuffer; +typedef VarBuffer TextPositionsI; -void SurfaceGDI::DrawTextCommon(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, UINT fuOptions) { +void SurfaceGDI::DrawTextCommon(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, UINT fuOptions) { SetFont(font_); const RECT rcw = RectFromPRectangle(rc); const int x = static_cast(rc.left); const int yBaseInt = static_cast(ybase); - if (unicodeMode) { - const TextWide tbuf(text, unicodeMode, codePage); + if (mode.codePage == SC_CP_UTF8) { + const TextWide tbuf(text, mode.codePage); ::ExtTextOutW(hdc, x, yBaseInt, fuOptions, &rcw, tbuf.buffer, tbuf.tlen, nullptr); } else { ::ExtTextOutA(hdc, x, yBaseInt, fuOptions, &rcw, text.data(), static_cast(text.length()), nullptr); } } -void SurfaceGDI::DrawTextNoClip(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, - ColourDesired fore, ColourDesired back) { - ::SetTextColor(hdc, fore.AsInteger()); - ::SetBkColor(hdc, back.AsInteger()); +void SurfaceGDI::DrawTextNoClip(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, + ColourAlpha fore, ColourAlpha back) { + ::SetTextColor(hdc, fore.GetColour().AsInteger()); + ::SetBkColor(hdc, back.GetColour().AsInteger()); DrawTextCommon(rc, font_, ybase, text, ETO_OPAQUE); } -void SurfaceGDI::DrawTextClipped(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, - ColourDesired fore, ColourDesired back) { - ::SetTextColor(hdc, fore.AsInteger()); - ::SetBkColor(hdc, back.AsInteger()); +void SurfaceGDI::DrawTextClipped(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, + ColourAlpha fore, ColourAlpha back) { + ::SetTextColor(hdc, fore.GetColour().AsInteger()); + ::SetBkColor(hdc, back.GetColour().AsInteger()); DrawTextCommon(rc, font_, ybase, text, ETO_OPAQUE | ETO_CLIPPED); } -void SurfaceGDI::DrawTextTransparent(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, - ColourDesired fore) { +void SurfaceGDI::DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, + ColourAlpha fore) { // Avoid drawing spaces in transparent mode for (const char ch : text) { if (ch != ' ') { - ::SetTextColor(hdc, fore.AsInteger()); + ::SetTextColor(hdc, fore.GetColour().AsInteger()); ::SetBkMode(hdc, TRANSPARENT); DrawTextCommon(rc, font_, ybase, text, 0); ::SetBkMode(hdc, OPAQUE); @@ -1083,28 +1066,16 @@ void SurfaceGDI::DrawTextTransparent(PRectangle rc, const Font &font_, XYPOSITIO } } -XYPOSITION SurfaceGDI::WidthText(const Font &font_, std::string_view text) { - SetFont(font_); - SIZE sz = { 0, 0 }; - if (!unicodeMode) { - ::GetTextExtentPoint32A(hdc, text.data(), std::min(static_cast(text.length()), maxLenText), &sz); - } else { - const TextWide tbuf(text, unicodeMode, codePage); - ::GetTextExtentPoint32W(hdc, tbuf.buffer, tbuf.tlen, &sz); - } - return static_cast(sz.cx); -} - -void SurfaceGDI::MeasureWidths(const Font &font_, std::string_view text, XYPOSITION *positions) { +void SurfaceGDI::MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) { // Zero positions to avoid random behaviour on failure. std::fill(positions, positions + text.length(), 0.0f); SetFont(font_); - SIZE sz = { 0, 0 }; + SIZE sz = { 0,0 }; int fit = 0; int i = 0; const int len = static_cast(text.length()); - if (unicodeMode) { - const TextWide tbuf(text, unicodeMode, codePage); + if (mode.codePage == SC_CP_UTF8) { + const TextWide tbuf(text, mode.codePage); TextPositionsI poses(tbuf.tlen); if (!::GetTextExtentExPointW(hdc, tbuf.buffer, tbuf.tlen, maxWidthMeasure, &fit, poses.buffer, &sz)) { // Failure @@ -1137,61 +1108,145 @@ void SurfaceGDI::MeasureWidths(const Font &font_, std::string_view text, XYPOSIT std::fill(positions + i, positions + text.length(), lastPos); } -XYPOSITION SurfaceGDI::Ascent(const Font &font_) noexcept { +XYPOSITION SurfaceGDI::WidthText(const Font *font_, std::string_view text) { + SetFont(font_); + SIZE sz = { 0,0 }; + if (!(mode.codePage == SC_CP_UTF8)) { + ::GetTextExtentPoint32A(hdc, text.data(), std::min(static_cast(text.length()), maxLenText), &sz); + } else { + const TextWide tbuf(text, mode.codePage); + ::GetTextExtentPoint32W(hdc, tbuf.buffer, tbuf.tlen, &sz); + } + return static_cast(sz.cx); +} + +void SurfaceGDI::DrawTextCommonUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, UINT fuOptions) { + SetFont(font_); + const RECT rcw = RectFromPRectangle(rc); + const int x = static_cast(rc.left); + const int yBaseInt = static_cast(ybase); + + const TextWide tbuf(text, SC_CP_UTF8); + ::ExtTextOutW(hdc, x, yBaseInt, fuOptions, &rcw, tbuf.buffer, tbuf.tlen, nullptr); +} + +void SurfaceGDI::DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, + ColourAlpha fore, ColourAlpha back) { + ::SetTextColor(hdc, fore.GetColour().AsInteger()); + ::SetBkColor(hdc, back.GetColour().AsInteger()); + DrawTextCommonUTF8(rc, font_, ybase, text, ETO_OPAQUE); +} + +void SurfaceGDI::DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, + ColourAlpha fore, ColourAlpha back) { + ::SetTextColor(hdc, fore.GetColour().AsInteger()); + ::SetBkColor(hdc, back.GetColour().AsInteger()); + DrawTextCommonUTF8(rc, font_, ybase, text, ETO_OPAQUE | ETO_CLIPPED); +} + +void SurfaceGDI::DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, + ColourAlpha fore) { + // Avoid drawing spaces in transparent mode + for (const char ch : text) { + if (ch != ' ') { + ::SetTextColor(hdc, fore.GetColour().AsInteger()); + ::SetBkMode(hdc, TRANSPARENT); + DrawTextCommonUTF8(rc, font_, ybase, text, 0); + ::SetBkMode(hdc, OPAQUE); + return; + } + } +} + +void SurfaceGDI::MeasureWidthsUTF8(const Font *font_, std::string_view text, XYPOSITION *positions) { + // Zero positions to avoid random behaviour on failure. + std::fill(positions, positions + text.length(), 0.0f); + SetFont(font_); + SIZE sz = { 0,0 }; + int fit = 0; + int i = 0; + const int len = static_cast(text.length()); + const TextWide tbuf(text, SC_CP_UTF8); + TextPositionsI poses(tbuf.tlen); + if (!::GetTextExtentExPointW(hdc, tbuf.buffer, tbuf.tlen, maxWidthMeasure, &fit, poses.buffer, &sz)) { + // Failure + return; + } + // Map the widths given for UTF-16 characters back onto the UTF-8 input string + for (int ui = 0; ui < fit; ui++) { + const unsigned char uch = text[i]; + const unsigned int byteCount = UTF8BytesOfLead[uch]; + if (byteCount == 4) { // Non-BMP + ui++; + } + for (unsigned int bytePos = 0; (bytePos < byteCount) && (i < len); bytePos++) { + positions[i++] = static_cast(poses.buffer[ui]); + } + } + // If any positions not filled in then use the last position for them + const XYPOSITION lastPos = (fit > 0) ? positions[fit - 1] : 0.0f; + std::fill(positions + i, positions + text.length(), lastPos); +} + +XYPOSITION SurfaceGDI::WidthTextUTF8(const Font *font_, std::string_view text) { + SetFont(font_); + SIZE sz = { 0,0 }; + const TextWide tbuf(text, SC_CP_UTF8); + ::GetTextExtentPoint32W(hdc, tbuf.buffer, tbuf.tlen, &sz); + return static_cast(sz.cx); +} + +XYPOSITION SurfaceGDI::Ascent(const Font *font_) { SetFont(font_); TEXTMETRIC tm; ::GetTextMetrics(hdc, &tm); return static_cast(tm.tmAscent); } -XYPOSITION SurfaceGDI::Descent(const Font &font_) noexcept { +XYPOSITION SurfaceGDI::Descent(const Font *font_) { SetFont(font_); TEXTMETRIC tm; ::GetTextMetrics(hdc, &tm); return static_cast(tm.tmDescent); } -XYPOSITION SurfaceGDI::InternalLeading(const Font &font_) noexcept { +XYPOSITION SurfaceGDI::InternalLeading(const Font *font_) { SetFont(font_); TEXTMETRIC tm; ::GetTextMetrics(hdc, &tm); return static_cast(tm.tmInternalLeading); } -XYPOSITION SurfaceGDI::Height(const Font &font_) noexcept { +XYPOSITION SurfaceGDI::Height(const Font *font_) { SetFont(font_); TEXTMETRIC tm; ::GetTextMetrics(hdc, &tm); return static_cast(tm.tmHeight); } -XYPOSITION SurfaceGDI::AverageCharWidth(const Font &font_) noexcept { +XYPOSITION SurfaceGDI::AverageCharWidth(const Font *font_) { SetFont(font_); TEXTMETRIC tm; ::GetTextMetrics(hdc, &tm); return static_cast(tm.tmAveCharWidth); } -void SurfaceGDI::SetClip(PRectangle rc) noexcept { +void SurfaceGDI::SetClip(PRectangle rc) { + ::SaveDC(hdc); ::IntersectClipRect(hdc, static_cast(rc.left), static_cast(rc.top), static_cast(rc.right), static_cast(rc.bottom)); } -void SurfaceGDI::FlushCachedState() noexcept { +void SurfaceGDI::PopClip() { + ::RestoreDC(hdc, -1); +} + +void SurfaceGDI::FlushCachedState() { pen = {}; brush = {}; } -void SurfaceGDI::SetUnicodeMode(bool unicodeMode_) noexcept { - unicodeMode = unicodeMode_; -} - -void SurfaceGDI::SetDBCSMode(int codePage_) noexcept { - // No action on window as automatically handled by system. - codePage = codePage_; -} - -void SurfaceGDI::SetBidiR2L(bool) noexcept { +void SurfaceGDI::FlushDrawing() { } #if defined(USE_D2D) @@ -1199,27 +1254,56 @@ void SurfaceGDI::SetBidiR2L(bool) noexcept { namespace { constexpr D2D1_RECT_F RectangleFromPRectangle(PRectangle rc) noexcept { - return { rc.left, rc.top, rc.right, rc.bottom }; + return { + static_cast(rc.left), + static_cast(rc.top), + static_cast(rc.right), + static_cast(rc.bottom) + }; +} + +constexpr D2D1_POINT_2F DPointFromPoint(Point point) noexcept { + return { static_cast(point.x), static_cast(point.y) }; +} + +const int SupportsD2D[] = { + SC_SUPPORTS_LINE_DRAWS_FINAL, + SC_SUPPORTS_FRACTIONAL_STROKE_WIDTH, + SC_SUPPORTS_TRANSLUCENT_STROKE, + SC_SUPPORTS_PIXEL_MODIFICATION, +}; + +constexpr D2D_COLOR_F ColorFromColourAlpha(ColourAlpha colour) noexcept { + return D2D_COLOR_F{ + colour.GetRedComponent(), + colour.GetGreenComponent(), + colour.GetBlueComponent(), + colour.GetAlphaComponent() + }; +} + +constexpr D2D1_RECT_F RectangleInset(D2D1_RECT_F rect, FLOAT inset) noexcept { + return D2D1_RECT_F{ + rect.left + inset, + rect.top + inset, + rect.right - inset, + rect.bottom - inset }; } } class BlobInline; -class SurfaceD2D final : public Surface { - bool unicodeMode = false; - int x = 0; - int y = 0; +class SurfaceD2D : public Surface { + SurfaceMode mode; - int codePage = 0; - int codePageText =0; + int codePageText = 0; ID2D1RenderTarget *pRenderTarget = nullptr; ID2D1BitmapRenderTarget *pBitmapRenderTarget = nullptr; bool ownRenderTarget = false; int clipsActive = 0; - // From selected font IDWriteTextFormat *pTextFormat = nullptr; FLOAT yAscent = 2; FLOAT yDescent = 1; @@ -1230,11 +1314,12 @@ class SurfaceD2D final : public Surface { int logPixelsY = USER_DEFAULT_SCREEN_DPI; void Clear() noexcept; - void SetFont(const Font &font_) noexcept; + void SetFont(const Font *font_) noexcept; HRESULT GetBitmap(ID2D1Bitmap **ppBitmap); public: - SurfaceD2D() noexcept = default; + SurfaceD2D() noexcept; + SurfaceD2D(ID2D1RenderTarget *pRenderTargetCompatible, int width, int height, SurfaceMode mode_, int logPixelsY_) noexcept; // Deleted so SurfaceD2D objects can not be copied. SurfaceD2D(const SurfaceD2D &) = delete; SurfaceD2D(SurfaceD2D &&) = delete; @@ -1242,55 +1327,89 @@ public: SurfaceD2D &operator=(SurfaceD2D &&) = delete; ~SurfaceD2D() noexcept override; - void Init(WindowID wid) noexcept override; - void Init(SurfaceID sid, WindowID wid, bool printing = false) noexcept override; - void InitPixMap(int width, int height, Surface *surface_, WindowID wid) noexcept override; + void SetScale(WindowID wid) noexcept; + void Init(WindowID wid) override; + void Init(SurfaceID sid, WindowID wid) override; + std::unique_ptr AllocatePixMap(int width, int height) override; + + void SetMode(SurfaceMode mode_) override; void Release() noexcept override; - bool Initialised() const noexcept override; + int Supports(int feature) noexcept override; + bool Initialised() override; - HRESULT FlushDrawing() const noexcept; - - void PenColour(ColourDesired fore) override; - void D2DPenColour(ColourDesired fore, int alpha = 255); - int LogPixelsY() const noexcept override; - int DeviceHeightFont(int points) const noexcept override; - void SCICALL MoveTo(int x_, int y_) noexcept override; - void SCICALL LineTo(int x_, int y_) noexcept override; - void SCICALL Polygon(const Point *pts, size_t npts, ColourDesired fore, ColourDesired back) override; - void SCICALL RectangleDraw(PRectangle rc, ColourDesired fore, ColourDesired back) override; - void SCICALL FillRectangle(PRectangle rc, ColourDesired back) override; - void SCICALL FillRectangle(PRectangle rc, Surface &surfacePattern) override; - void SCICALL RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back) override; - void SCICALL AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill, - ColourDesired outline, int alphaOutline, int flags) override; - void SCICALL GradientRectangle(PRectangle rc, const std::vector &stops, GradientOptions options) override; - void SCICALL DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) override; - void SCICALL Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back) override; - void SCICALL Copy(PRectangle rc, Point from, Surface &surfaceSource) override; + void D2DPenColourAlpha(ColourAlpha fore) noexcept; + int LogPixelsY() override; + int PixelDivisions() override; + int DeviceHeightFont(int points) override; + void LineDraw(Point start, Point end, Stroke stroke) override; + ID2D1PathGeometry *Geometry(const Point *pts, size_t npts, D2D1_FIGURE_BEGIN figureBegin) noexcept; + void PolyLine(const Point *pts, size_t npts, Stroke stroke) override; + void Polygon(const Point *pts, size_t npts, FillStroke fillStroke) override; + void RectangleDraw(PRectangle rc, FillStroke fillStroke) override; + void RectangleFrame(PRectangle rc, Stroke stroke) override; + void FillRectangle(PRectangle rc, Fill fill) override; + void FillRectangleAligned(PRectangle rc, Fill fill) override; + void FillRectangle(PRectangle rc, Surface &surfacePattern) override; + void RoundedRectangle(PRectangle rc, FillStroke fillStroke) override; + void AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) override; + void GradientRectangle(PRectangle rc, const std::vector &stops, GradientOptions options) override; + void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) override; + void Ellipse(PRectangle rc, FillStroke fillStroke) override; + void Stadium(PRectangle rc, FillStroke fillStroke, Ends ends) override; + void Copy(PRectangle rc, Point from, Surface &surfaceSource) override; std::unique_ptr Layout(const IScreenLine *screenLine) override; - void SCICALL DrawTextCommon(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, UINT fuOptions); - void SCICALL DrawTextNoClip(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) override; - void SCICALL DrawTextClipped(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) override; - void SCICALL DrawTextTransparent(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, ColourDesired fore) override; - void SCICALL MeasureWidths(const Font &font_, std::string_view text, XYPOSITION *positions) override; - XYPOSITION WidthText(const Font &font_, std::string_view text) override; - XYPOSITION Ascent(const Font &font_) noexcept override; - XYPOSITION Descent(const Font &font_) noexcept override; - XYPOSITION InternalLeading(const Font &font_) noexcept override; - XYPOSITION Height(const Font &font_) noexcept override; - XYPOSITION AverageCharWidth(const Font &font_) override; + void DrawTextCommon(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, int codePageDraw, UINT fuOptions); - void SCICALL SetClip(PRectangle rc) noexcept override; - void FlushCachedState() noexcept override; + void DrawTextNoClip(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore, ColourAlpha back) override; + void DrawTextClipped(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore, ColourAlpha back) override; + void DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore) override; + void MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) override; + XYPOSITION WidthText(const Font *font_, std::string_view text) override; - void SetUnicodeMode(bool unicodeMode_) noexcept override; - void SetDBCSMode(int codePage_) noexcept override; - void SetBidiR2L(bool bidiR2L_) noexcept override; + void DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore, ColourAlpha back) override; + void DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore, ColourAlpha back) override; + void DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourAlpha fore) override; + void MeasureWidthsUTF8(const Font *font_, std::string_view text, XYPOSITION *positions) override; + XYPOSITION WidthTextUTF8(const Font *font_, std::string_view text) override; + + XYPOSITION Ascent(const Font *font_) override; + XYPOSITION Descent(const Font *font_) override; + XYPOSITION InternalLeading(const Font *font_) override; + XYPOSITION Height(const Font *font_) override; + XYPOSITION AverageCharWidth(const Font *font_) override; + + void SetClip(PRectangle rc) override; + void PopClip() override; + void FlushCachedState() override; + void FlushDrawing() override; }; +SurfaceD2D::SurfaceD2D() noexcept { +} + +SurfaceD2D::SurfaceD2D(ID2D1RenderTarget *pRenderTargetCompatible, int width, int height, SurfaceMode mode_, int logPixelsY_) noexcept { + const D2D1_SIZE_F desiredSize = D2D1::SizeF(static_cast(width), static_cast(height)); + D2D1_PIXEL_FORMAT desiredFormat; +#ifdef __MINGW32__ + desiredFormat.format = DXGI_FORMAT_UNKNOWN; +#else + desiredFormat = pRenderTargetCompatible->GetPixelFormat(); +#endif + desiredFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE; + const HRESULT hr = pRenderTargetCompatible->CreateCompatibleRenderTarget( + &desiredSize, nullptr, &desiredFormat, D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE, &pBitmapRenderTarget); + if (SUCCEEDED(hr)) { + pRenderTarget = pBitmapRenderTarget; + pRenderTarget->BeginDraw(); + ownRenderTarget = true; + } + mode = mode_; + logPixelsY = logPixelsY_; +} + SurfaceD2D::~SurfaceD2D() noexcept { Clear(); } @@ -1316,49 +1435,39 @@ void SurfaceD2D::Release() noexcept { Clear(); } -bool SurfaceD2D::Initialised() const noexcept { +void SurfaceD2D::SetScale(WindowID wid) noexcept { + logPixelsY = DpiForWindow(wid); +} + +int SurfaceD2D::Supports(int feature) noexcept { + for (const int f : SupportsD2D) { + if (f == feature) + return 1; + } + return 0; +} + +bool SurfaceD2D::Initialised() { return pRenderTarget != nullptr; } -HRESULT SurfaceD2D::FlushDrawing() const noexcept { - return pRenderTarget->Flush(); +void SurfaceD2D::Init(WindowID wid) { + Release(); + SetScale(wid); } -void SurfaceD2D::Init(WindowID wid) noexcept { +void SurfaceD2D::Init(SurfaceID sid, WindowID wid) { Release(); - logPixelsY = DpiYForWindow(wid); -} - -void SurfaceD2D::Init(SurfaceID sid, WindowID wid, bool printing /*=false*/) noexcept { - Release(); - // printing always using GDI technology - logPixelsY = DpiYForWindow(wid); + SetScale(wid); pRenderTarget = static_cast(sid); } -void SurfaceD2D::InitPixMap(int width, int height, Surface *surface_, WindowID wid) noexcept { - Release(); - logPixelsY = DpiYForWindow(wid); - SurfaceD2D *psurfOther = down_cast(surface_); - // Should only ever be called with a SurfaceD2D, not a SurfaceGDI - PLATFORM_ASSERT(psurfOther); - const D2D1_SIZE_F desiredSize = D2D1::SizeF(static_cast(width), static_cast(height)); - D2D1_PIXEL_FORMAT desiredFormat; -#ifdef __MINGW32__ - desiredFormat.format = DXGI_FORMAT_UNKNOWN; -#else - desiredFormat = psurfOther->pRenderTarget->GetPixelFormat(); -#endif - desiredFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE; - const HRESULT hr = psurfOther->pRenderTarget->CreateCompatibleRenderTarget( - &desiredSize, nullptr, &desiredFormat, D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE, &pBitmapRenderTarget); - if (SUCCEEDED(hr)) { - pRenderTarget = pBitmapRenderTarget; - pRenderTarget->BeginDraw(); - ownRenderTarget = true; - } - SetUnicodeMode(psurfOther->unicodeMode); - SetDBCSMode(psurfOther->codePage); +std::unique_ptr SurfaceD2D::AllocatePixMap(int width, int height) { + return std::make_unique(pRenderTarget, width, height, mode, logPixelsY); +} + +void SurfaceD2D::SetMode(SurfaceMode mode_) { + mode = mode_; } HRESULT SurfaceD2D::GetBitmap(ID2D1Bitmap **ppBitmap) { @@ -1366,17 +1475,9 @@ HRESULT SurfaceD2D::GetBitmap(ID2D1Bitmap **ppBitmap) { return pBitmapRenderTarget->GetBitmap(ppBitmap); } -void SurfaceD2D::PenColour(ColourDesired fore) { - D2DPenColour(fore); -} - -void SurfaceD2D::D2DPenColour(ColourDesired fore, int alpha) { +void SurfaceD2D::D2DPenColourAlpha(ColourAlpha fore) noexcept { if (pRenderTarget) { - D2D_COLOR_F col; - col.r = fore.GetRedComponent(); - col.g = fore.GetGreenComponent(); - col.b = fore.GetBlueComponent(); - col.a = alpha / 255.0f; + const D2D_COLOR_F col = ColorFromColourAlpha(fore); if (pBrush) { pBrush->SetColor(col); } else { @@ -1388,16 +1489,16 @@ void SurfaceD2D::D2DPenColour(ColourDesired fore, int alpha) { } } -void SurfaceD2D::SetFont(const Font &font_) noexcept { - const FormatAndMetrics *pfm = FamFromFontID(font_.GetID()); - PLATFORM_ASSERT(pfm->technology == SCWIN_TECH_DIRECTWRITE); +void SurfaceD2D::SetFont(const Font *font_) noexcept { + const FontDirectWrite *pfm = dynamic_cast(font_); + PLATFORM_ASSERT(pfm); pTextFormat = pfm->pTextFormat; yAscent = pfm->yAscent; yDescent = pfm->yDescent; yInternalLeading = pfm->yInternalLeading; - codePageText = codePage; - if (!unicodeMode && pfm->characterSet) { - codePageText = Scintilla::CodePageFromCharSet(pfm->characterSet, codePage); + codePageText = mode.codePage; + if (!(mode.codePage == SC_CP_UTF8) && pfm->characterSet) { + codePageText = Scintilla::CodePageFromCharSet(pfm->characterSet, mode.codePage); } if (pRenderTarget) { D2D1_TEXT_ANTIALIAS_MODE aaMode; @@ -1412,207 +1513,231 @@ void SurfaceD2D::SetFont(const Font &font_) noexcept { } } -int SurfaceD2D::LogPixelsY() const noexcept { +int SurfaceD2D::LogPixelsY() { return logPixelsY; } -int SurfaceD2D::DeviceHeightFont(int points) const noexcept { - return ::MulDiv(points, logPixelsY, 72); +int SurfaceD2D::PixelDivisions() { + // Win32 uses device pixels. + return 1; } -void SurfaceD2D::MoveTo(int x_, int y_) noexcept { - x = x_; - y = y_; +int SurfaceD2D::DeviceHeightFont(int points) { + return ::MulDiv(points, LogPixelsY(), 72); } -static constexpr int Delta(int difference) noexcept { - if (difference < 0) - return -1; - else if (difference > 0) - return 1; - else - return 0; -} +void SurfaceD2D::LineDraw(Point start, Point end, Stroke stroke) { + D2DPenColourAlpha(stroke.colour); -void SurfaceD2D::LineTo(int x_, int y_) noexcept { - if (pRenderTarget) { - const int xDiff = x_ - x; - const int xDelta = Delta(xDiff); - const int yDiff = y_ - y; - const int yDelta = Delta(yDiff); - if ((xDiff == 0) || (yDiff == 0)) { - // Horizontal or vertical lines can be more precisely drawn as a filled rectangle - const int xEnd = x_ - xDelta; - const int left = std::min(x, xEnd); - const int width = std::abs(x - xEnd) + 1; - const int yEnd = y_ - yDelta; - const int top = std::min(y, yEnd); - const int height = std::abs(y - yEnd) + 1; - const D2D1_RECT_F rectangle1 = D2D1::RectF(static_cast(left), static_cast(top), - static_cast(left + width), static_cast(top + height)); - pRenderTarget->FillRectangle(&rectangle1, pBrush); - } else if ((std::abs(xDiff) == std::abs(yDiff))) { - // 45 degree slope - pRenderTarget->DrawLine(D2D1::Point2F(x + 0.5f, y + 0.5f), - D2D1::Point2F(x_ + 0.5f - xDelta, y_ + 0.5f - yDelta), pBrush); - } else { - // Line has a different slope so difficult to avoid last pixel - pRenderTarget->DrawLine(D2D1::Point2F(x + 0.5f, y + 0.5f), - D2D1::Point2F(x_ + 0.5f, y_ + 0.5f), pBrush); - } - x = x_; - y = y_; + D2D1_STROKE_STYLE_PROPERTIES strokeProps {}; + strokeProps.startCap = D2D1_CAP_STYLE_SQUARE; + strokeProps.endCap = D2D1_CAP_STYLE_SQUARE; + strokeProps.dashCap = D2D1_CAP_STYLE_FLAT; + strokeProps.lineJoin = D2D1_LINE_JOIN_MITER; + strokeProps.miterLimit = 4.0f; + strokeProps.dashStyle = D2D1_DASH_STYLE_SOLID; + strokeProps.dashOffset = 0; + + // get the stroke style to apply + ID2D1StrokeStyle *pStrokeStyle = nullptr; + const HRESULT hr = pD2DFactory->CreateStrokeStyle( + strokeProps, nullptr, 0, &pStrokeStyle); + if (SUCCEEDED(hr)) { + pRenderTarget->DrawLine( + DPointFromPoint(start), + DPointFromPoint(end), pBrush, stroke.WidthF(), pStrokeStyle); } + + ReleaseUnknown(pStrokeStyle); } -void SurfaceD2D::Polygon(const Point *pts, size_t npts, ColourDesired fore, ColourDesired back) { +ID2D1PathGeometry *SurfaceD2D::Geometry(const Point *pts, size_t npts, D2D1_FIGURE_BEGIN figureBegin) noexcept { + ID2D1PathGeometry *geometry = nullptr; + HRESULT hr = pD2DFactory->CreatePathGeometry(&geometry); + if (SUCCEEDED(hr) && geometry) { + ID2D1GeometrySink *sink = nullptr; + hr = geometry->Open(&sink); + if (SUCCEEDED(hr) && sink) { + sink->BeginFigure(DPointFromPoint(pts[0]), figureBegin); + for (size_t i = 1; i < npts; i++) { + sink->AddLine(DPointFromPoint(pts[i])); + } + sink->EndFigure((figureBegin == D2D1_FIGURE_BEGIN_FILLED) ? + D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN); + sink->Close(); + ReleaseUnknown(sink); + } + } + return geometry; +} + +void SurfaceD2D::PolyLine(const Point *pts, size_t npts, Stroke stroke) { + PLATFORM_ASSERT(pRenderTarget && (npts > 1)); + if (!pRenderTarget || (npts <= 1)) { + return; + } + + ID2D1PathGeometry *geometry = Geometry(pts, npts, D2D1_FIGURE_BEGIN_HOLLOW); + PLATFORM_ASSERT(geometry); + if (!geometry) { + return; + } + + D2DPenColourAlpha(stroke.colour); + D2D1_STROKE_STYLE_PROPERTIES strokeProps {}; + strokeProps.startCap = D2D1_CAP_STYLE_ROUND; + strokeProps.endCap = D2D1_CAP_STYLE_ROUND; + strokeProps.dashCap = D2D1_CAP_STYLE_FLAT; + strokeProps.lineJoin = D2D1_LINE_JOIN_MITER; + strokeProps.miterLimit = 4.0f; + strokeProps.dashStyle = D2D1_DASH_STYLE_SOLID; + strokeProps.dashOffset = 0; + + // get the stroke style to apply + ID2D1StrokeStyle *pStrokeStyle = nullptr; + const HRESULT hr = pD2DFactory->CreateStrokeStyle( + strokeProps, nullptr, 0, &pStrokeStyle); + if (SUCCEEDED(hr)) { + pRenderTarget->DrawGeometry(geometry, pBrush, stroke.WidthF(), pStrokeStyle); + } + ReleaseUnknown(pStrokeStyle); + ReleaseUnknown(geometry); +} + +void SurfaceD2D::Polygon(const Point *pts, size_t npts, FillStroke fillStroke) { PLATFORM_ASSERT(pRenderTarget && (npts > 2)); if (pRenderTarget) { - ID2D1PathGeometry *geometry = nullptr; - HRESULT hr = pD2DFactory->CreatePathGeometry(&geometry); + ID2D1PathGeometry *geometry = Geometry(pts, npts, D2D1_FIGURE_BEGIN_FILLED); PLATFORM_ASSERT(geometry); - if (SUCCEEDED(hr) && geometry) { - ID2D1GeometrySink *sink = nullptr; - hr = geometry->Open(&sink); - if (SUCCEEDED(hr) && sink) { - sink->BeginFigure(D2D1::Point2F(pts[0].x + 0.5f, pts[0].y + 0.5f), D2D1_FIGURE_BEGIN_FILLED); - for (size_t i = 1; i < npts; i++) { - sink->AddLine(D2D1::Point2F(pts[i].x + 0.5f, pts[i].y + 0.5f)); - } - sink->EndFigure(D2D1_FIGURE_END_CLOSED); - sink->Close(); - ReleaseUnknown(sink); - - D2DPenColour(back); - pRenderTarget->FillGeometry(geometry, pBrush); - D2DPenColour(fore); - pRenderTarget->DrawGeometry(geometry, pBrush); - } + if (geometry) { + D2DPenColourAlpha(fillStroke.fill.colour); + pRenderTarget->FillGeometry(geometry, pBrush); + D2DPenColourAlpha(fillStroke.stroke.colour); + pRenderTarget->DrawGeometry(geometry, pBrush, fillStroke.stroke.WidthF()); + ReleaseUnknown(geometry); } - ReleaseUnknown(geometry); } } -void SurfaceD2D::RectangleDraw(PRectangle rc, ColourDesired fore, ColourDesired back) { +void SurfaceD2D::RectangleDraw(PRectangle rc, FillStroke fillStroke) { + if (!pRenderTarget) + return; + const D2D1_RECT_F rect = RectangleFromPRectangle(rc); + const D2D1_RECT_F rectFill = RectangleInset(rect, fillStroke.stroke.WidthF()); + const float halfStroke = fillStroke.stroke.WidthF() / 2.0f; + const D2D1_RECT_F rectOutline = RectangleInset(rect, halfStroke); + + D2DPenColourAlpha(fillStroke.fill.colour); + pRenderTarget->FillRectangle(&rectFill, pBrush); + D2DPenColourAlpha(fillStroke.stroke.colour); + pRenderTarget->DrawRectangle(&rectOutline, pBrush, fillStroke.stroke.WidthF()); +} + +void SurfaceD2D::RectangleFrame(PRectangle rc, Stroke stroke) { if (pRenderTarget) { - const D2D1_RECT_F rectangle1 = D2D1::RectF(std::round(rc.left) + 0.5f, rc.top + 0.5f, std::round(rc.right) - 0.5f, rc.bottom - 0.5f); - D2DPenColour(back); - pRenderTarget->FillRectangle(&rectangle1, pBrush); - D2DPenColour(fore); - pRenderTarget->DrawRectangle(&rectangle1, pBrush); + const XYPOSITION halfStroke = stroke.width / 2.0f; + const D2D1_RECT_F rectangle1 = RectangleFromPRectangle(rc.Inset(halfStroke)); + D2DPenColourAlpha(stroke.colour); + pRenderTarget->DrawRectangle(&rectangle1, pBrush, stroke.WidthF()); } } -void SurfaceD2D::FillRectangle(PRectangle rc, ColourDesired back) { +void SurfaceD2D::FillRectangle(PRectangle rc, Fill fill) { if (pRenderTarget) { - D2DPenColour(back); - const D2D1_RECT_F rectangle1 = D2D1::RectF(std::round(rc.left), rc.top, std::round(rc.right), rc.bottom); - pRenderTarget->FillRectangle(&rectangle1, pBrush); + D2DPenColourAlpha(fill.colour); + const D2D1_RECT_F rectangle = RectangleFromPRectangle(rc); + pRenderTarget->FillRectangle(&rectangle, pBrush); } } +void SurfaceD2D::FillRectangleAligned(PRectangle rc, Fill fill) { + FillRectangle(PixelAlign(rc, 1), fill); +} + void SurfaceD2D::FillRectangle(PRectangle rc, Surface &surfacePattern) { - SurfaceD2D *psurfOther = down_cast(&surfacePattern); + SurfaceD2D *psurfOther = dynamic_cast(&surfacePattern); PLATFORM_ASSERT(psurfOther); - psurfOther->FlushDrawing(); ID2D1Bitmap *pBitmap = nullptr; HRESULT hr = psurfOther->GetBitmap(&pBitmap); if (SUCCEEDED(hr) && pBitmap) { ID2D1BitmapBrush *pBitmapBrush = nullptr; const D2D1_BITMAP_BRUSH_PROPERTIES brushProperties = - D2D1::BitmapBrushProperties(D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP, - D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR); + D2D1::BitmapBrushProperties(D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP, + D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR); // Create the bitmap brush. hr = pRenderTarget->CreateBitmapBrush(pBitmap, brushProperties, &pBitmapBrush); + ReleaseUnknown(pBitmap); if (SUCCEEDED(hr) && pBitmapBrush) { pRenderTarget->FillRectangle( - D2D1::RectF(rc.left, rc.top, rc.right, rc.bottom), + RectangleFromPRectangle(rc), pBitmapBrush); + ReleaseUnknown(pBitmapBrush); } - ReleaseUnknown(pBitmapBrush); } - ReleaseUnknown(pBitmap); } -void SurfaceD2D::RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back) { +void SurfaceD2D::RoundedRectangle(PRectangle rc, FillStroke fillStroke) { if (pRenderTarget) { D2D1_ROUNDED_RECT roundedRectFill = { - D2D1::RectF(rc.left + 1.0f, rc.top + 1.0f, rc.right - 1.0f, rc.bottom - 1.0f), - 4, 4 }; - D2DPenColour(back); + RectangleFromPRectangle(rc.Inset(1.0)), + 4, 4}; + D2DPenColourAlpha(fillStroke.fill.colour); pRenderTarget->FillRoundedRectangle(roundedRectFill, pBrush); D2D1_ROUNDED_RECT roundedRect = { - D2D1::RectF(rc.left + 0.5f, rc.top + 0.5f, rc.right - 0.5f, rc.bottom - 0.5f), - 4, 4 }; - D2DPenColour(fore); - pRenderTarget->DrawRoundedRectangle(roundedRect, pBrush); + RectangleFromPRectangle(rc.Inset(0.5)), + 4, 4}; + D2DPenColourAlpha(fillStroke.stroke.colour); + pRenderTarget->DrawRoundedRectangle(roundedRect, pBrush, fillStroke.stroke.WidthF()); } } -void SurfaceD2D::AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill, - ColourDesired outline, int alphaOutline, int /* flags*/) { +void SurfaceD2D::AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) { + const D2D1_RECT_F rect = RectangleFromPRectangle(rc); + const D2D1_RECT_F rectFill = RectangleInset(rect, fillStroke.stroke.WidthF()); + const float halfStroke = fillStroke.stroke.WidthF() / 2.0f; + const D2D1_RECT_F rectOutline = RectangleInset(rect, halfStroke); if (pRenderTarget) { - float const left = std::round(rc.left); - float const right = std::round(rc.right); if (cornerSize == 0) { // When corner size is zero, draw square rectangle to prevent blurry pixels at corners - const D2D1_RECT_F rectFill = D2D1::RectF(left + 1.0f, rc.top + 1.0f, right - 1.0f, rc.bottom - 1.0f); - D2DPenColour(fill, alphaFill); + D2DPenColourAlpha(fillStroke.fill.colour); pRenderTarget->FillRectangle(rectFill, pBrush); - const D2D1_RECT_F rectOutline = D2D1::RectF(left + 0.5f, rc.top + 0.5f, right - 0.5f, rc.bottom - 0.5f); - D2DPenColour(outline, alphaOutline); - pRenderTarget->DrawRectangle(rectOutline, pBrush); + D2DPenColourAlpha(fillStroke.stroke.colour); + pRenderTarget->DrawRectangle(rectOutline, pBrush, fillStroke.stroke.WidthF()); } else { const float cornerSizeF = static_cast(cornerSize); D2D1_ROUNDED_RECT roundedRectFill = { - D2D1::RectF(left + 1.0f, rc.top + 1.0f, right - 1.0f, rc.bottom - 1.0f), - cornerSizeF - 1.0f, cornerSizeF - 1.0f }; - D2DPenColour(fill, alphaFill); + rectFill, cornerSizeF - 1.0f, cornerSizeF - 1.0f }; + D2DPenColourAlpha(fillStroke.fill.colour); pRenderTarget->FillRoundedRectangle(roundedRectFill, pBrush); D2D1_ROUNDED_RECT roundedRect = { - D2D1::RectF(left + 0.5f, rc.top + 0.5f, right - 0.5f, rc.bottom - 0.5f), - cornerSizeF, cornerSizeF }; - D2DPenColour(outline, alphaOutline); - pRenderTarget->DrawRoundedRectangle(roundedRect, pBrush); + rectOutline, cornerSizeF, cornerSizeF}; + D2DPenColourAlpha(fillStroke.stroke.colour); + pRenderTarget->DrawRoundedRectangle(roundedRect, pBrush, fillStroke.stroke.WidthF()); } } } -namespace { - -constexpr D2D_COLOR_F ColorFromColourAlpha(ColourAlpha colour) noexcept { - D2D_COLOR_F col = { - colour.GetRedComponent(), - colour.GetGreenComponent(), - colour.GetBlueComponent(), - colour.GetAlphaComponent() - }; - return col; -} - -} - void SurfaceD2D::GradientRectangle(PRectangle rc, const std::vector &stops, GradientOptions options) { if (pRenderTarget) { - D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES lgbp; - lgbp.startPoint = D2D1::Point2F(rc.left, rc.top); + D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES lgbp { + DPointFromPoint(Point(rc.left, rc.top)), {} + }; switch (options) { case GradientOptions::leftToRight: - lgbp.endPoint = D2D1::Point2F(rc.right, rc.top); + lgbp.endPoint = DPointFromPoint(Point(rc.right, rc.top)); break; case GradientOptions::topToBottom: default: - lgbp.endPoint = D2D1::Point2F(rc.left, rc.bottom); + lgbp.endPoint = DPointFromPoint(Point(rc.left, rc.bottom)); break; } std::vector gradientStops; - gradientStops.reserve(stops.size()); for (const ColourStop &stop : stops) { - gradientStops.push_back({ stop.position, ColorFromColourAlpha(stop.colour) }); + gradientStops.push_back({ static_cast(stop.position), ColorFromColourAlpha(stop.colour) }); } ID2D1GradientStopCollection *pGradientStops = nullptr; HRESULT hr = pRenderTarget->CreateGradientStopCollection( @@ -1624,7 +1749,8 @@ void SurfaceD2D::GradientRectangle(PRectangle rc, const std::vector hr = pRenderTarget->CreateLinearGradientBrush( lgbp, pGradientStops, &pBrushLinear); if (SUCCEEDED(hr) && pBrushLinear) { - const D2D1_RECT_F rectangle = D2D1::RectF(std::round(rc.left), rc.top, std::round(rc.right), rc.bottom); + const D2D1_RECT_F rectangle = RectangleFromPRectangle(PRectangle( + std::round(rc.left), rc.top, std::round(rc.right), rc.bottom)); pRenderTarget->FillRectangle(&rectangle, pBrushLinear); ReleaseUnknown(pBrushLinear); } @@ -1646,57 +1772,153 @@ void SurfaceD2D::DrawRGBAImage(PRectangle rc, int width, int height, const unsig ID2D1Bitmap *bitmap = nullptr; const D2D1_SIZE_U size = D2D1::SizeU(width, height); - D2D1_BITMAP_PROPERTIES props = { {DXGI_FORMAT_B8G8R8A8_UNORM, - D2D1_ALPHA_MODE_PREMULTIPLIED}, 72.0, 72.0 }; + D2D1_BITMAP_PROPERTIES props = {{DXGI_FORMAT_B8G8R8A8_UNORM, + D2D1_ALPHA_MODE_PREMULTIPLIED}, 72.0, 72.0}; const HRESULT hr = pRenderTarget->CreateBitmap(size, image.data(), - width * 4, &props, &bitmap); + width * 4, &props, &bitmap); if (SUCCEEDED(hr)) { const D2D1_RECT_F rcDestination = RectangleFromPRectangle(rc); pRenderTarget->DrawBitmap(bitmap, rcDestination); + ReleaseUnknown(bitmap); } - ReleaseUnknown(bitmap); } } -void SurfaceD2D::Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back) { - if (pRenderTarget) { - const FLOAT radius = rc.Width() / 2.0f; - D2D1_ELLIPSE ellipse = { - D2D1::Point2F((rc.left + rc.right) / 2.0f, (rc.top + rc.bottom) / 2.0f), - radius, radius }; +void SurfaceD2D::Ellipse(PRectangle rc, FillStroke fillStroke) { + if (!pRenderTarget) + return; + const D2D1_POINT_2F centre = DPointFromPoint(rc.Centre()); - PenColour(back); - pRenderTarget->FillEllipse(ellipse, pBrush); - PenColour(fore); - pRenderTarget->DrawEllipse(ellipse, pBrush); + const FLOAT radiusFill = static_cast(rc.Width() / 2.0f - fillStroke.stroke.width); + const D2D1_ELLIPSE ellipseFill = { centre, radiusFill, radiusFill }; + + D2DPenColourAlpha(fillStroke.fill.colour); + pRenderTarget->FillEllipse(ellipseFill, pBrush); + + const FLOAT radiusOutline = static_cast(rc.Width() / 2.0f - fillStroke.stroke.width / 2.0f); + const D2D1_ELLIPSE ellipseOutline = { centre, radiusOutline, radiusOutline }; + + D2DPenColourAlpha(fillStroke.stroke.colour); + pRenderTarget->DrawEllipse(ellipseOutline, pBrush, fillStroke.stroke.WidthF()); +} + +void SurfaceD2D::Stadium(PRectangle rc, FillStroke fillStroke, Ends ends) { + if (!pRenderTarget) + return; + if (rc.Width() < rc.Height()) { + // Can't draw nice ends so just draw a rectangle + RectangleDraw(rc, fillStroke); + return; + } + const FLOAT radius = static_cast(rc.Height() / 2.0); + const FLOAT radiusFill = radius - fillStroke.stroke.WidthF(); + const FLOAT halfStroke = fillStroke.stroke.WidthF() / 2.0f; + if (ends == Surface::Ends::semiCircles) { + const D2D1_RECT_F rect = RectangleFromPRectangle(rc); + D2D1_ROUNDED_RECT roundedRectFill = { RectangleInset(rect, fillStroke.stroke.WidthF()), + radiusFill, radiusFill }; + D2DPenColourAlpha(fillStroke.fill.colour); + pRenderTarget->FillRoundedRectangle(roundedRectFill, pBrush); + + D2D1_ROUNDED_RECT roundedRect = { RectangleInset(rect, halfStroke), + radius, radius }; + D2DPenColourAlpha(fillStroke.stroke.colour); + pRenderTarget->DrawRoundedRectangle(roundedRect, pBrush, fillStroke.stroke.WidthF()); + } else { + const Ends leftSide = static_cast(static_cast(ends) & 0xf); + const Ends rightSide = static_cast(static_cast(ends) & 0xf0); + PRectangle rcInner = rc; + rcInner.left += radius; + rcInner.right -= radius; + ID2D1PathGeometry *pathGeometry = nullptr; + const HRESULT hrGeometry = pD2DFactory->CreatePathGeometry(&pathGeometry); + if (FAILED(hrGeometry) || !pathGeometry) + return; + ID2D1GeometrySink *pSink = nullptr; + const HRESULT hrSink = pathGeometry->Open(&pSink); + if (SUCCEEDED(hrSink) && pSink) { + switch (leftSide) { + case Ends::leftFlat: + pSink->BeginFigure(DPointFromPoint(Point(rc.left + halfStroke, rc.top + halfStroke)), D2D1_FIGURE_BEGIN_FILLED); + pSink->AddLine(DPointFromPoint(Point(rc.left + halfStroke, rc.bottom - halfStroke))); + break; + case Ends::leftAngle: + pSink->BeginFigure(DPointFromPoint(Point(rcInner.left + halfStroke, rc.top + halfStroke)), D2D1_FIGURE_BEGIN_FILLED); + pSink->AddLine(DPointFromPoint(Point(rc.left + halfStroke, rc.Centre().y))); + pSink->AddLine(DPointFromPoint(Point(rcInner.left + halfStroke, rc.bottom - halfStroke))); + break; + case Ends::semiCircles: + default: { + pSink->BeginFigure(DPointFromPoint(Point(rcInner.left + halfStroke, rc.top + halfStroke)), D2D1_FIGURE_BEGIN_FILLED); + D2D1_ARC_SEGMENT segment{}; + segment.point = DPointFromPoint(Point(rcInner.left + halfStroke, rc.bottom - halfStroke)); + segment.size = D2D1::SizeF(radiusFill, radiusFill); + segment.rotationAngle = 0.0f; + segment.sweepDirection = D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE; + segment.arcSize = D2D1_ARC_SIZE_SMALL; + pSink->AddArc(segment); + } + break; + } + + switch (rightSide) { + case Ends::rightFlat: + pSink->AddLine(DPointFromPoint(Point(rc.right - halfStroke, rc.bottom - halfStroke))); + pSink->AddLine(DPointFromPoint(Point(rc.right - halfStroke, rc.top + halfStroke))); + break; + case Ends::rightAngle: + pSink->AddLine(DPointFromPoint(Point(rcInner.right - halfStroke, rc.bottom - halfStroke))); + pSink->AddLine(DPointFromPoint(Point(rc.right - halfStroke, rc.Centre().y))); + pSink->AddLine(DPointFromPoint(Point(rcInner.right - halfStroke, rc.top + halfStroke))); + break; + case Ends::semiCircles: + default: { + pSink->AddLine(DPointFromPoint(Point(rcInner.right - halfStroke, rc.bottom - halfStroke))); + D2D1_ARC_SEGMENT segment{}; + segment.point = DPointFromPoint(Point(rcInner.right - halfStroke, rc.top + halfStroke)); + segment.size = D2D1::SizeF(radiusFill, radiusFill); + segment.rotationAngle = 0.0f; + segment.sweepDirection = D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE; + segment.arcSize = D2D1_ARC_SIZE_SMALL; + pSink->AddArc(segment); + } + break; + } + + pSink->EndFigure(D2D1_FIGURE_END_CLOSED); + + pSink->Close(); + } + ReleaseUnknown(pSink); + D2DPenColourAlpha(fillStroke.fill.colour); + pRenderTarget->FillGeometry(pathGeometry, pBrush); + D2DPenColourAlpha(fillStroke.stroke.colour); + pRenderTarget->DrawGeometry(pathGeometry, pBrush, fillStroke.stroke.WidthF()); + ReleaseUnknown(pathGeometry); } } void SurfaceD2D::Copy(PRectangle rc, Point from, Surface &surfaceSource) { SurfaceD2D &surfOther = dynamic_cast(surfaceSource); - surfOther.FlushDrawing(); ID2D1Bitmap *pBitmap = nullptr; - HRESULT hr = surfOther.GetBitmap(&pBitmap); + const HRESULT hr = surfOther.GetBitmap(&pBitmap); if (SUCCEEDED(hr) && pBitmap) { const D2D1_RECT_F rcDestination = RectangleFromPRectangle(rc); - D2D1_RECT_F rcSource = { from.x, from.y, from.x + rc.Width(), from.y + rc.Height() }; + D2D1_RECT_F rcSource = RectangleFromPRectangle(PRectangle( + from.x, from.y, from.x + rc.Width(), from.y + rc.Height())); pRenderTarget->DrawBitmap(pBitmap, rcDestination, 1.0f, D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR, rcSource); - hr = pRenderTarget->Flush(); - if (FAILED(hr)) { - //Platform::DebugPrintf("Failed Flush 0x%lx\n", hr); - } + ReleaseUnknown(pBitmap); } - ReleaseUnknown(pBitmap); } class BlobInline : public IDWriteInlineObject { XYPOSITION width; // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, PVOID *ppv) noexcept override; - STDMETHODIMP_(ULONG)AddRef() noexcept override; - STDMETHODIMP_(ULONG)Release() noexcept override; + STDMETHODIMP QueryInterface(REFIID riid, PVOID *ppv) override; + STDMETHODIMP_(ULONG)AddRef() override; + STDMETHODIMP_(ULONG)Release() override; // IDWriteInlineObject COM_DECLSPEC_NOTHROW STDMETHODIMP Draw( @@ -1707,39 +1929,44 @@ class BlobInline : public IDWriteInlineObject { BOOL isSideways, BOOL isRightToLeft, IUnknown *clientDrawingEffect - ) override; + ) override; COM_DECLSPEC_NOTHROW STDMETHODIMP GetMetrics(DWRITE_INLINE_OBJECT_METRICS *metrics) override; COM_DECLSPEC_NOTHROW STDMETHODIMP GetOverhangMetrics(DWRITE_OVERHANG_METRICS *overhangs) override; COM_DECLSPEC_NOTHROW STDMETHODIMP GetBreakConditions( DWRITE_BREAK_CONDITION *breakConditionBefore, DWRITE_BREAK_CONDITION *breakConditionAfter) override; public: - explicit BlobInline(XYPOSITION width_ = 0.0f) noexcept : width(width_) {} - virtual ~BlobInline() = default; + BlobInline(XYPOSITION width_=0.0f) noexcept : width(width_) { + } + // Defaulted so BlobInline objects can be copied. + BlobInline(const BlobInline &) = default; + BlobInline(BlobInline &&) = default; + BlobInline &operator=(const BlobInline &) = default; + BlobInline &operator=(BlobInline &&) = default; + virtual ~BlobInline() noexcept = default; }; /// Implement IUnknown -STDMETHODIMP BlobInline::QueryInterface(REFIID riid, PVOID *ppv) noexcept { - if (!ppv) { +STDMETHODIMP BlobInline::QueryInterface(REFIID riid, PVOID *ppv) { + if (!ppv) return E_POINTER; - } // Never called so not checked. *ppv = nullptr; if (riid == IID_IUnknown) - *ppv = this; + *ppv = static_cast(this); if (riid == __uuidof(IDWriteInlineObject)) - *ppv = this; + *ppv = static_cast(this); if (!*ppv) return E_NOINTERFACE; return S_OK; } -STDMETHODIMP_(ULONG) BlobInline::AddRef() noexcept { +STDMETHODIMP_(ULONG) BlobInline::AddRef() { // Lifetime tied to Platform methods so ignore any reference operations. return 1; } -STDMETHODIMP_(ULONG) BlobInline::Release() noexcept { +STDMETHODIMP_(ULONG) BlobInline::Release() { // Lifetime tied to Platform methods so ignore any reference operations. return 1; } @@ -1762,10 +1989,9 @@ COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE BlobInline::Draw( COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE BlobInline::GetMetrics( DWRITE_INLINE_OBJECT_METRICS *metrics ) { - if (!metrics) { + if (!metrics) return E_POINTER; - } - metrics->width = width; + metrics->width = static_cast(width); metrics->height = 2; metrics->baseline = 1; metrics->supportsSideways = FALSE; @@ -1775,9 +2001,8 @@ COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE BlobInline::GetMetrics( COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE BlobInline::GetOverhangMetrics( DWRITE_OVERHANG_METRICS *overhangs ) { - if (!overhangs) { + if (!overhangs) return E_POINTER; - } overhangs->left = 0; overhangs->top = 0; overhangs->right = 0; @@ -1789,9 +2014,8 @@ COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE BlobInline::GetBreakConditions( DWRITE_BREAK_CONDITION *breakConditionBefore, DWRITE_BREAK_CONDITION *breakConditionAfter ) { - if (!breakConditionBefore || !breakConditionAfter) { + if (!breakConditionBefore || !breakConditionAfter) return E_POINTER; - } // Since not performing 2D layout, not necessary to implement *breakConditionBefore = DWRITE_BREAK_CONDITION_NEUTRAL; *breakConditionAfter = DWRITE_BREAK_CONDITION_NEUTRAL; @@ -1805,16 +2029,16 @@ class ScreenLineLayout : public IScreenLineLayout { std::vector blobs; static void FillTextLayoutFormats(const IScreenLine *screenLine, IDWriteTextLayout *textLayout, std::vector &blobs); static std::wstring ReplaceRepresentation(std::string_view text); - static size_t GetPositionInLayout(std::string_view text, size_t position) noexcept; + static size_t GetPositionInLayout(std::string_view text, size_t position); public: - explicit ScreenLineLayout(const IScreenLine *screenLine); + ScreenLineLayout(const IScreenLine *screenLine); // Deleted so ScreenLineLayout objects can not be copied ScreenLineLayout(const ScreenLineLayout &) = delete; ScreenLineLayout(ScreenLineLayout &&) = delete; ScreenLineLayout &operator=(const ScreenLineLayout &) = delete; ScreenLineLayout &operator=(ScreenLineLayout &&) = delete; - ~ScreenLineLayout() override; - size_t PositionFromX(XYPOSITION xDistance, bool charPosition) noexcept override; + ~ScreenLineLayout() noexcept override; + size_t PositionFromX(XYPOSITION xDistance, bool charPosition) override; XYPOSITION XFromPosition(size_t caretPosition) noexcept override; std::vector FindRangeIntervals(size_t start, size_t end) override; }; @@ -1839,7 +2063,7 @@ void ScreenLineLayout::FillTextLayoutFormats(const IScreenLine *screenLine, IDWr XYPOSITION representationWidth = screenLine->RepresentationWidth(bytePosition); if ((representationWidth == 0.0f) && (screenLine->Text()[bytePosition] == '\t')) { - Point realPt; + D2D1_POINT_2F realPt {}; DWRITE_HIT_TEST_METRICS realCaretMetrics {}; textLayout->HitTestTextPosition( layoutPosition, @@ -1853,16 +2077,15 @@ void ScreenLineLayout::FillTextLayoutFormats(const IScreenLine *screenLine, IDWr representationWidth = nextTab - realPt.x; } if (representationWidth > 0.0f) { - blobs.emplace_back(representationWidth); + blobs.push_back(BlobInline(representationWidth)); textLayout->SetInlineObject(&blobs.back(), textRange); }; - FormatAndMetrics *pfm = - static_cast(screenLine->FontOfPosition(bytePosition)->GetID()); - - const UINT32 fontFamilyNameSize = pfm->pTextFormat->GetFontFamilyNameLength(); - std::wstring fontFamilyName(fontFamilyNameSize + 1, L'\0'); + const FontDirectWrite *pfm = + dynamic_cast(screenLine->FontOfPosition(bytePosition)); + const unsigned int fontFamilyNameSize = pfm->pTextFormat->GetFontFamilyNameLength(); + std::wstring fontFamilyName(fontFamilyNameSize, 0); const HRESULT hrFamily = pfm->pTextFormat->GetFontFamilyName(fontFamilyName.data(), fontFamilyNameSize + 1); if (SUCCEEDED(hrFamily)) { textLayout->SetFontFamilyName(fontFamilyName.c_str(), textRange); @@ -1872,10 +2095,9 @@ void ScreenLineLayout::FillTextLayoutFormats(const IScreenLine *screenLine, IDWr textLayout->SetFontWeight(pfm->pTextFormat->GetFontWeight(), textRange); textLayout->SetFontStyle(pfm->pTextFormat->GetFontStyle(), textRange); - const UINT32 localeNameSize = pfm->pTextFormat->GetLocaleNameLength(); - std::wstring localeName(localeNameSize + 1, L'\0'); - - const HRESULT hrLocale = pfm->pTextFormat->GetLocaleName(localeName.data(), localeNameSize); + const unsigned int localeNameSize = pfm->pTextFormat->GetLocaleNameLength(); + std::wstring localeName(localeNameSize, 0); + const HRESULT hrLocale = pfm->pTextFormat->GetLocaleName(localeName.data(), localeNameSize + 1); if (SUCCEEDED(hrLocale)) { textLayout->SetLocaleName(localeName.c_str(), textRange); } @@ -1896,7 +2118,7 @@ void ScreenLineLayout::FillTextLayoutFormats(const IScreenLine *screenLine, IDWr /* Convert to a wide character string and replace tabs with X to stop DirectWrite tab expansion */ std::wstring ScreenLineLayout::ReplaceRepresentation(std::string_view text) { - const TextWide wideText(text, true); + const TextWide wideText(text, SC_CP_UTF8); std::wstring ws(wideText.buffer, wideText.tlen); std::replace(ws.begin(), ws.end(), L'\t', L'X'); return ws; @@ -1904,21 +2126,20 @@ std::wstring ScreenLineLayout::ReplaceRepresentation(std::string_view text) { // Finds the position in the wide character version of the text. -size_t ScreenLineLayout::GetPositionInLayout(std::string_view text, size_t position) noexcept { +size_t ScreenLineLayout::GetPositionInLayout(std::string_view text, size_t position) { const std::string_view textUptoPosition = text.substr(0, position); return UTF16Length(textUptoPosition); } ScreenLineLayout::ScreenLineLayout(const IScreenLine *screenLine) { // If the text is empty, then no need to go through this function - if (!screenLine || !screenLine->Length()) { + if (!screenLine || !screenLine->Length()) return; - } text = screenLine->Text(); // Get textFormat - FormatAndMetrics *pfm = static_cast(screenLine->FontOfPosition(0)->GetID()); + const FontDirectWrite *pfm = dynamic_cast(screenLine->FontOfPosition(0)); if (!pIDWriteFactory || !pfm->pTextFormat) { return; @@ -1928,8 +2149,13 @@ ScreenLineLayout::ScreenLineLayout(const IScreenLine *screenLine) { buffer = ReplaceRepresentation(screenLine->Text()); // Create a text layout - const HRESULT hrCreate = pIDWriteFactory->CreateTextLayout(buffer.c_str(), static_cast(buffer.length()), - pfm->pTextFormat, screenLine->Width(), screenLine->Height(), &textLayout); + const HRESULT hrCreate = pIDWriteFactory->CreateTextLayout( + buffer.c_str(), + static_cast(buffer.length()), + pfm->pTextFormat, + static_cast(screenLine->Width()), + static_cast(screenLine->Height()), + &textLayout); if (!SUCCEEDED(hrCreate)) { return; } @@ -1938,18 +2164,18 @@ ScreenLineLayout::ScreenLineLayout(const IScreenLine *screenLine) { FillTextLayoutFormats(screenLine, textLayout, blobs); } -ScreenLineLayout::~ScreenLineLayout() { +ScreenLineLayout::~ScreenLineLayout() noexcept { ReleaseUnknown(textLayout); } // Get the position from the provided x -size_t ScreenLineLayout::PositionFromX(XYPOSITION xDistance, bool charPosition) noexcept { +size_t ScreenLineLayout::PositionFromX(XYPOSITION xDistance, bool charPosition) { if (!textLayout) { return 0; } - // Returns the text position corresponding to the mouse (x, y). + // Returns the text position corresponding to the mouse x,y. // If hitting the trailing side of a cluster, return the // leading edge of the following text position. @@ -1958,7 +2184,7 @@ size_t ScreenLineLayout::PositionFromX(XYPOSITION xDistance, bool charPosition) DWRITE_HIT_TEST_METRICS caretMetrics {}; textLayout->HitTestPoint( - xDistance, + static_cast(xDistance), 0.0f, &isTrailingHit, &isInside, @@ -2004,9 +2230,9 @@ XYPOSITION ScreenLineLayout::XFromPosition(size_t caretPosition) noexcept { // Convert byte positions to wchar_t positions const size_t position = GetPositionInLayout(text, caretPosition); - // Translate text character offset to point (x, y). + // Translate text character offset to point x,y. DWRITE_HIT_TEST_METRICS caretMetrics {}; - Point pt {}; + D2D1_POINT_2F pt {}; textLayout->HitTestTextPosition( static_cast(position), @@ -2069,15 +2295,11 @@ std::vector ScreenLineLayout::FindRangeIntervals(size_t start, size_t } // Get the selection ranges behind the text. - ret.reserve(actualHitTestCount); + for (size_t i = 0; i < actualHitTestCount; ++i) { // Store selection rectangle const DWRITE_HIT_TEST_METRICS &htm = hitTestMetrics[i]; - Interval selectionInterval; - - selectionInterval.left = htm.left; - selectionInterval.right = htm.left + htm.width; - + const Interval selectionInterval { htm.left, htm.left + htm.width }; ret.push_back(selectionInterval); } @@ -2088,11 +2310,11 @@ std::unique_ptr SurfaceD2D::Layout(const IScreenLine *screenL return std::make_unique(screenLine); } -void SurfaceD2D::DrawTextCommon(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, UINT fuOptions) { +void SurfaceD2D::DrawTextCommon(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, int codePageDraw, UINT fuOptions) { SetFont(font_); // Use Unicode calls - const TextWide tbuf(text, unicodeMode, codePageText); + const TextWide tbuf(text, codePageDraw); if (pRenderTarget && pTextFormat && pBrush) { if (fuOptions & ETO_CLIPPED) { const D2D1_RECT_F rcClip = RectangleFromPRectangle(rc); @@ -2101,10 +2323,15 @@ void SurfaceD2D::DrawTextCommon(PRectangle rc, const Font &font_, XYPOSITION yba // Explicitly creating a text layout appears a little faster IDWriteTextLayout *pTextLayout = nullptr; - const HRESULT hr = pIDWriteFactory->CreateTextLayout(tbuf.buffer, tbuf.tlen, pTextFormat, - rc.Width(), rc.Height(), &pTextLayout); + const HRESULT hr = pIDWriteFactory->CreateTextLayout( + tbuf.buffer, + tbuf.tlen, + pTextFormat, + static_cast(rc.Width()), + static_cast(rc.Height()), + &pTextLayout); if (SUCCEEDED(hr)) { - D2D1_POINT_2F origin = { rc.left, ybase - yAscent }; + D2D1_POINT_2F origin = DPointFromPoint(Point(rc.left, ybase-yAscent)); pRenderTarget->DrawTextLayout(origin, pTextLayout, pBrush, d2dDrawTextOptions); ReleaseUnknown(pTextLayout); } @@ -2115,42 +2342,123 @@ void SurfaceD2D::DrawTextCommon(PRectangle rc, const Font &font_, XYPOSITION yba } } -void SurfaceD2D::DrawTextNoClip(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, - ColourDesired fore, ColourDesired back) { +void SurfaceD2D::DrawTextNoClip(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, + ColourAlpha fore, ColourAlpha back) { if (pRenderTarget) { - FillRectangle(rc, back); - D2DPenColour(fore); - DrawTextCommon(rc, font_, ybase, text, ETO_OPAQUE); + FillRectangleAligned(rc, back); + D2DPenColourAlpha(fore); + DrawTextCommon(rc, font_, ybase, text, codePageText, ETO_OPAQUE); } } -void SurfaceD2D::DrawTextClipped(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, - ColourDesired fore, ColourDesired back) { +void SurfaceD2D::DrawTextClipped(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, + ColourAlpha fore, ColourAlpha back) { if (pRenderTarget) { - FillRectangle(rc, back); - D2DPenColour(fore); - DrawTextCommon(rc, font_, ybase, text, ETO_OPAQUE | ETO_CLIPPED); + FillRectangleAligned(rc, back); + D2DPenColourAlpha(fore); + DrawTextCommon(rc, font_, ybase, text, codePageText, ETO_OPAQUE | ETO_CLIPPED); } } -void SurfaceD2D::DrawTextTransparent(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, - ColourDesired fore) { +void SurfaceD2D::DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, + ColourAlpha fore) { // Avoid drawing spaces in transparent mode for (const char ch : text) { if (ch != ' ') { if (pRenderTarget) { - D2DPenColour(fore); - DrawTextCommon(rc, font_, ybase, text, 0); + D2DPenColourAlpha(fore); + DrawTextCommon(rc, font_, ybase, text, codePageText, 0); } return; } } } -XYPOSITION SurfaceD2D::WidthText(const Font &font_, std::string_view text) { +void SurfaceD2D::MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) { + SetFont(font_); + if (!pIDWriteFactory || !pTextFormat) { + // SetFont failed or no access to DirectWrite so give up. + return; + } + const TextWide tbuf(text, codePageText); + TextPositions poses(tbuf.tlen); + // Initialize poses for safety. + std::fill(poses.buffer, poses.buffer + tbuf.tlen, 0.0f); + // Create a layout + IDWriteTextLayout *pTextLayout = nullptr; + const HRESULT hrCreate = pIDWriteFactory->CreateTextLayout(tbuf.buffer, tbuf.tlen, pTextFormat, 10000.0, 1000.0, &pTextLayout); + if (!SUCCEEDED(hrCreate) || !pTextLayout) { + return; + } + constexpr int clusters = stackBufferLength; + DWRITE_CLUSTER_METRICS clusterMetrics[clusters]; + UINT32 count = 0; + const HRESULT hrGetCluster = pTextLayout->GetClusterMetrics(clusterMetrics, clusters, &count); + ReleaseUnknown(pTextLayout); + if (!SUCCEEDED(hrGetCluster)) { + return; + } + // A cluster may be more than one WCHAR, such as for "ffi" which is a ligature in the Candara font + FLOAT position = 0.0f; + int ti=0; + for (unsigned int ci=0; ci 0) + lastPos = positions[i-1]; + while (i(tbuf.tlen)); + for (int kk=0; kk 0) - lastPos = positions[i - 1]; - while (i < text.length()) { - positions[i++] = lastPos; - } - } else { -#if 0 - const DBCSCharClassify *dbcs = DBCSCharClassify::Get(codePageText); - if (dbcs) { - // May be one or two bytes per position - int ui = 0; - for (size_t i = 0; i < text.length() && ui < tbuf.tlen;) { - positions[i] = poses.buffer[ui]; - if (dbcs->IsLeadByte(text[i])) { - positions[i + 1] = poses.buffer[ui]; - i += 2; - } else { - i++; - } - - ui++; - } - } else -#endif - { - // One char per position - PLATFORM_ASSERT(text.length() == static_cast(tbuf.tlen)); - for (int kk = 0; kk < tbuf.tlen; kk++) { - positions[kk] = poses.buffer[kk]; - } + for (unsigned int bytePos=0; (bytePos 0) + lastPos = positions[i - 1]; + while (i < text.length()) { + positions[i++] = lastPos; } } -XYPOSITION SurfaceD2D::Ascent(const Font &font_) noexcept { +XYPOSITION SurfaceD2D::WidthTextUTF8(const Font * font_, std::string_view text) { + FLOAT width = 1.0; + SetFont(font_); + const TextWide tbuf(text, SC_CP_UTF8); + if (pIDWriteFactory && pTextFormat) { + // Create a layout + IDWriteTextLayout *pTextLayout = nullptr; + const HRESULT hr = pIDWriteFactory->CreateTextLayout(tbuf.buffer, tbuf.tlen, pTextFormat, 1000.0, 1000.0, &pTextLayout); + if (SUCCEEDED(hr)) { + DWRITE_TEXT_METRICS textMetrics; + if (SUCCEEDED(pTextLayout->GetMetrics(&textMetrics))) + width = textMetrics.widthIncludingTrailingWhitespace; + ReleaseUnknown(pTextLayout); + } + } + return width; +} + +XYPOSITION SurfaceD2D::Ascent(const Font *font_) { SetFont(font_); return std::ceil(yAscent); } -XYPOSITION SurfaceD2D::Descent(const Font &font_) noexcept { +XYPOSITION SurfaceD2D::Descent(const Font *font_) { SetFont(font_); return std::ceil(yDescent); } -XYPOSITION SurfaceD2D::InternalLeading(const Font &font_) noexcept { +XYPOSITION SurfaceD2D::InternalLeading(const Font *font_) { SetFont(font_); return std::floor(yInternalLeading); } -XYPOSITION SurfaceD2D::Height(const Font &font_) noexcept { +XYPOSITION SurfaceD2D::Height(const Font *font_) { return Ascent(font_) + Descent(font_); } -XYPOSITION SurfaceD2D::AverageCharWidth(const Font &font_) { +XYPOSITION SurfaceD2D::AverageCharWidth(const Font *font_) { FLOAT width = 1.0; SetFont(font_); if (pIDWriteFactory && pTextFormat) { // Create a layout IDWriteTextLayout *pTextLayout = nullptr; - const WCHAR wszAllAlpha[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - constexpr size_t lenAllAlpha = (sizeof(wszAllAlpha) / sizeof(WCHAR)) - 1; + static const WCHAR wszAllAlpha[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const size_t lenAllAlpha = wcslen(wszAllAlpha); const HRESULT hr = pIDWriteFactory->CreateTextLayout(wszAllAlpha, static_cast(lenAllAlpha), pTextFormat, 1000.0, 1000.0, &pTextLayout); if (SUCCEEDED(hr) && pTextLayout) { @@ -2290,7 +2618,7 @@ XYPOSITION SurfaceD2D::AverageCharWidth(const Font &font_) { return width; } -void SurfaceD2D::SetClip(PRectangle rc) noexcept { +void SurfaceD2D::SetClip(PRectangle rc) { if (pRenderTarget) { const D2D1_RECT_F rcClip = RectangleFromPRectangle(rc); pRenderTarget->PushAxisAlignedClip(rcClip, D2D1_ANTIALIAS_MODE_ALIASED); @@ -2298,35 +2626,38 @@ void SurfaceD2D::SetClip(PRectangle rc) noexcept { } } -void SurfaceD2D::FlushCachedState() noexcept { +void SurfaceD2D::PopClip() { + if (pRenderTarget) { + PLATFORM_ASSERT(clipsActive > 0); + pRenderTarget->PopAxisAlignedClip(); + clipsActive--; + } } -void SurfaceD2D::SetUnicodeMode(bool unicodeMode_) noexcept { - unicodeMode = unicodeMode_; +void SurfaceD2D::FlushCachedState() { } -void SurfaceD2D::SetDBCSMode(int codePage_) noexcept { - // No action on window as automatically handled by system. - codePage = codePage_; -} - -void SurfaceD2D::SetBidiR2L(bool) noexcept { +void SurfaceD2D::FlushDrawing() { + if (pRenderTarget) { + pRenderTarget->Flush(); + } } #endif -Surface *Surface::Allocate(int technology) { +std::unique_ptr Surface::Allocate(int technology) { #if defined(USE_D2D) if (technology == SCWIN_TECH_GDI) - return new SurfaceGDI; + return std::make_unique(); else - return new SurfaceD2D; + return std::make_unique(); #else - return new SurfaceGDI; + return std::make_unique(); #endif } -Window::~Window() = default; +Window::~Window() noexcept { +} void Window::Destroy() noexcept { if (wid) @@ -2334,28 +2665,28 @@ void Window::Destroy() noexcept { wid = nullptr; } -PRectangle Window::GetPosition() const noexcept { +PRectangle Window::GetPosition() const { RECT rc; ::GetWindowRect(HwndFromWindowID(wid), &rc); return PRectangle::FromInts(rc.left, rc.top, rc.right, rc.bottom); } -void Window::SetPosition(PRectangle rc) noexcept { +void Window::SetPosition(PRectangle rc) { ::SetWindowPos(HwndFromWindowID(wid), - nullptr, static_cast(rc.left), static_cast(rc.top), + 0, static_cast(rc.left), static_cast(rc.top), static_cast(rc.Width()), static_cast(rc.Height()), SWP_NOZORDER | SWP_NOACTIVATE); } namespace { -RECT RectFromMonitor(HMONITOR hMonitor) noexcept { +static RECT RectFromMonitor(HMONITOR hMonitor) noexcept { MONITORINFO mi = {}; mi.cbSize = sizeof(mi); if (GetMonitorInfo(hMonitor, &mi)) { return mi.rcWork; } - RECT rc = { 0, 0, 0, 0 }; - if (::SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0) == 0) { + RECT rc = {0, 0, 0, 0}; + if (::SystemParametersInfoA(SPI_GETWORKAREA, 0, &rc, 0) == 0) { rc.left = 0; rc.top = 0; rc.right = 0; @@ -2366,10 +2697,10 @@ RECT RectFromMonitor(HMONITOR hMonitor) noexcept { } -void Window::SetPositionRelative(PRectangle rc, const Window *relativeTo) noexcept { +void Window::SetPositionRelative(PRectangle rc, const Window *relativeTo) { const DWORD style = GetWindowStyle(HwndFromWindowID(wid)); if (style & WS_POPUP) { - POINT ptOther = { 0, 0 }; + POINT ptOther = {0, 0}; ::ClientToScreen(HwndFromWindow(*relativeTo), &ptOther); rc.Move(static_cast(ptOther.x), static_cast(ptOther.y)); @@ -2397,33 +2728,29 @@ void Window::SetPositionRelative(PRectangle rc, const Window *relativeTo) noexce SetPosition(rc); } -PRectangle Window::GetClientPosition() const noexcept { - RECT rc = { 0, 0, 0, 0 }; +PRectangle Window::GetClientPosition() const { + RECT rc={0,0,0,0}; if (wid) ::GetClientRect(HwndFromWindowID(wid), &rc); return PRectangle::FromInts(rc.left, rc.top, rc.right, rc.bottom); } -void Window::Show(bool show) const noexcept { +void Window::Show(bool show) { if (show) ::ShowWindow(HwndFromWindowID(wid), SW_SHOWNOACTIVATE); else ::ShowWindow(HwndFromWindowID(wid), SW_HIDE); } -void Window::InvalidateAll() noexcept { +void Window::InvalidateAll() { ::InvalidateRect(HwndFromWindowID(wid), nullptr, FALSE); } -void Window::InvalidateRectangle(PRectangle rc) noexcept { +void Window::InvalidateRectangle(PRectangle rc) { const RECT rcw = RectFromPRectangle(rc); ::InvalidateRect(HwndFromWindowID(wid), &rcw, FALSE); } -void Window::SetFont(const Font &font) noexcept { - SetWindowFont(HwndFromWindowID(wid), font.GetID(), FALSE); -} - namespace { void FlipBitmap(HBITMAP bitmap, int width, int height) noexcept { @@ -2438,15 +2765,15 @@ void FlipBitmap(HBITMAP bitmap, int width, int height) noexcept { } -HCURSOR LoadReverseArrowCursor(DPI_T dpi) noexcept { - HCURSOR reverseArrowCursor{}; +HCURSOR LoadReverseArrowCursor(UINT dpi) noexcept { + HCURSOR reverseArrowCursor {}; bool created = false; HCURSOR cursor = ::LoadCursor({}, IDC_ARROW); - if (dpi.y != g_uSystemDPI) { - const int width = SystemMetricsForDpi(SM_CXCURSOR, dpi.x); - const int height = SystemMetricsForDpi(SM_CYCURSOR, dpi.y); + if (dpi != uSystemDPI) { + const int width = SystemMetricsForDpi(SM_CXCURSOR, dpi); + const int height = SystemMetricsForDpi(SM_CYCURSOR, dpi); HCURSOR copy = static_cast(::CopyImage(cursor, IMAGE_CURSOR, width, height, LR_COPYFROMRESOURCE | LR_COPYRETURNORG)); if (copy) { created = copy != cursor; @@ -2456,7 +2783,7 @@ HCURSOR LoadReverseArrowCursor(DPI_T dpi) noexcept { ICONINFO info; if (::GetIconInfo(cursor, &info)) { - BITMAP bmp; + BITMAP bmp {}; if (::GetObject(info.hbmMask, sizeof(bmp), &bmp)) { FlipBitmap(info.hbmMask, bmp.bmWidth, bmp.bmHeight); if (info.hbmColor) @@ -2477,45 +2804,45 @@ HCURSOR LoadReverseArrowCursor(DPI_T dpi) noexcept { return reverseArrowCursor; } -void Window::SetCursor(Cursor curs) noexcept { +void Window::SetCursor(Cursor curs) { switch (curs) { - case Cursor::cursorText: - ::SetCursor(::LoadCursor({}, IDC_IBEAM)); + case Cursor::text: + ::SetCursor(::LoadCursor(NULL,IDC_IBEAM)); break; - case Cursor::cursorUp: - ::SetCursor(::LoadCursor({}, IDC_UPARROW)); + case Cursor::up: + ::SetCursor(::LoadCursor(NULL,IDC_UPARROW)); break; - case Cursor::cursorWait: - ::SetCursor(::LoadCursor({}, IDC_WAIT)); + case Cursor::wait: + ::SetCursor(::LoadCursor(NULL,IDC_WAIT)); break; - case Cursor::cursorHoriz: - ::SetCursor(::LoadCursor({}, IDC_SIZEWE)); + case Cursor::horizontal: + ::SetCursor(::LoadCursor(NULL,IDC_SIZEWE)); break; - case Cursor::cursorVert: - ::SetCursor(::LoadCursor({}, IDC_SIZENS)); + case Cursor::vertical: + ::SetCursor(::LoadCursor(NULL,IDC_SIZENS)); break; - case Cursor::cursorHand: - ::SetCursor(::LoadCursor({}, IDC_HAND)); + case Cursor::hand: + ::SetCursor(::LoadCursor(NULL,IDC_HAND)); break; - case Cursor::cursorReverseArrow: - case Cursor::cursorArrow: - case Cursor::cursorInvalid: // Should not occur, but just in case. - ::SetCursor(::LoadCursor({}, IDC_ARROW)); + case Cursor::reverseArrow: + case Cursor::arrow: + case Cursor::invalid: // Should not occur, but just in case. + ::SetCursor(::LoadCursor(NULL,IDC_ARROW)); break; } } /* Returns rectangle of monitor pt is on, both rect and pt are in Window's coordinates */ -PRectangle Window::GetMonitorRect(Point pt) const noexcept { +PRectangle Window::GetMonitorRect(Point pt) { const PRectangle rcPosition = GetPosition(); - POINT ptDesktop = { static_cast(pt.x + rcPosition.left), - static_cast(pt.y + rcPosition.top) }; + POINT ptDesktop = {static_cast(pt.x + rcPosition.left), + static_cast(pt.y + rcPosition.top)}; HMONITOR hMonitor = MonitorFromPoint(ptDesktop, MONITOR_DEFAULTTONEAREST); const RECT rcWork = RectFromMonitor(hMonitor); if (rcWork.left < rcWork.right) { - const PRectangle rcMonitor( + PRectangle rcMonitor( rcWork.left - rcPosition.left, rcWork.top - rcPosition.top, rcWork.right - rcPosition.left, @@ -2546,7 +2873,7 @@ public: if (index < data.size()) { return data[index]; } else { - ListItemData missing = { "", -1 }; + ListItemData missing = {"", -1}; return missing; } } @@ -2559,24 +2886,23 @@ public: data.push_back(lid); } - char *SetWords(const char *s, size_t length) { - words = std::vector(s, s + length + 1); - return words.data(); + char *SetWords(const char *s) { + words = std::vector(s, s+strlen(s)+1); + return &words[0]; } }; -static const TCHAR *ListBoxX_ClassName = L"ListBoxX"; -#define LISTBOXX_USE_THICKFRAME 0 -#define LISTBOXX_USE_BORDER 1 -#define LISTBOXX_USE_FAKE_FRAME 0 +const TCHAR ListBoxX_ClassName[] = TEXT("ListBoxX"); -ListBox::ListBox() noexcept = default; +ListBox::ListBox() noexcept { +} -ListBox::~ListBox() = default; +ListBox::~ListBox() noexcept { +} -class ListBoxX final : public ListBox { +class ListBoxX : public ListBox { int lineHeight; - FontID fontCopy; + HFONT fontCopy; int technology; RGBAImageSet images; LineToItem lti; @@ -2585,12 +2911,9 @@ class ListBoxX final : public ListBox { int desiredVisibleRows; unsigned int maxItemCharacters; unsigned int aveCharWidth; - COLORREF colorText; - COLORREF colorBackground; - HBRUSH hbrBackground; Window *parent; int ctrlID; - DPI_T dpi; + UINT dpi; IListBoxDelegate *delegate; const char *widestItem; unsigned int maxCharWidth; @@ -2599,6 +2922,7 @@ class ListBoxX final : public ListBox { Point dragOffset; Point location; // Caret location at which the list is opened int wheelDelta; // mouse wheel residue + ListOptions options; HWND GetHWND() const noexcept; void AppendListItem(const char *text, const char *numword); @@ -2613,11 +2937,11 @@ class ListBoxX final : public ListBox { void OnDoubleClick(); void OnSelChange(); void ResizeToCursor(); - void StartResize(WPARAM) noexcept; - LRESULT NcHitTest(WPARAM, LPARAM) const noexcept; + void StartResize(WPARAM); + LRESULT NcHitTest(WPARAM, LPARAM) const; void CentreItem(int n); - void Paint(HDC) noexcept; - static LRESULT CALLBACK ControlWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData); + void Paint(HDC); + static LRESULT PASCAL ControlWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam); static constexpr Point ItemInset {0, 0}; // Padding around whole item static constexpr Point TextInset {2, 0}; // Padding around text @@ -2626,55 +2950,50 @@ class ListBoxX final : public ListBox { public: ListBoxX() noexcept : lineHeight(10), fontCopy{}, technology(0), lb{}, unicodeMode(false), desiredVisibleRows(9), maxItemCharacters(0), aveCharWidth(8), - colorText(0), colorBackground(0), hbrBackground{}, - parent(nullptr), ctrlID(0), dpi({ USER_DEFAULT_SCREEN_DPI, USER_DEFAULT_SCREEN_DPI }), + parent(nullptr), ctrlID(0), dpi(USER_DEFAULT_SCREEN_DPI), delegate(nullptr), - widestItem(nullptr), maxCharWidth(1), resizeHit(0), wheelDelta(0) {} - ~ListBoxX() override { + widestItem(nullptr), maxCharWidth(1), resizeHit(0), wheelDelta(0) { + } + ListBoxX(const ListBoxX &) = delete; + ListBoxX(ListBoxX &&) = delete; + ListBoxX &operator=(const ListBoxX &) = delete; + ListBoxX &operator=(ListBoxX &&) = delete; + ~ListBoxX() noexcept override { if (fontCopy) { ::DeleteObject(fontCopy); - fontCopy = nullptr; - } - if (hbrBackground) { - ::DeleteObject(hbrBackground); - hbrBackground = nullptr; + fontCopy = 0; } } - void SetFont(const Font &font) noexcept override; - void SetColour(ColourDesired fore, ColourDesired back) noexcept override; - void SCICALL Create(Window &parent_, int ctrlID_, Point location_, int lineHeight_, bool unicodeMode_, int technology_) noexcept override; - void SetAverageCharWidth(int width) noexcept override; - void SetVisibleRows(int rows) noexcept override; - int GetVisibleRows() const noexcept override; + void SetFont(const Font *font) override; + void Create(Window &parent_, int ctrlID_, Point location_, int lineHeight_, bool unicodeMode_, int technology_) override; + void SetAverageCharWidth(int width) override; + void SetVisibleRows(int rows) override; + int GetVisibleRows() const override; PRectangle GetDesiredRect() override; - int CaretFromEdge() const override; + int CaretFromEdge() override; void Clear() noexcept override; - void Append(const char *s, int type = -1) const noexcept override; - int Length() const noexcept override; + void Append(char *s, int type = -1) override; + int Length() override; void Select(int n) override; - int GetSelection() const noexcept override; - int Find(const char *prefix) const noexcept override; - void GetValue(int n, char *value, int len) const noexcept override; + int GetSelection() override; + int Find(const char *prefix) override; + std::string GetValue(int n) override; void RegisterImage(int type, const char *xpm_data) override; void RegisterRGBAImage(int type, int width, int height, const unsigned char *pixelsImage) override; - void ClearRegisteredImages() noexcept override; - void SetDelegate(IListBoxDelegate *lbDelegate) noexcept override; + void ClearRegisteredImages() override; + void SetDelegate(IListBoxDelegate *lbDelegate) override; void SetList(const char *list, char separator, char typesep) override; - void Draw(const DRAWITEMSTRUCT *pDrawItem); + void SetOptions(ListOptions options_) override; + void Draw(DRAWITEMSTRUCT *pDrawItem); LRESULT WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam); - static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam); + static LRESULT PASCAL StaticWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam); }; -#if LISTBOXX_USE_FAKE_FRAME -constexpr int ListBoxXFakeFrameSize = 4; -#endif - -ListBox *ListBox::Allocate() { - ListBoxX *lb = new ListBoxX(); - return lb; +std::unique_ptr ListBox::Allocate() { + return std::make_unique(); } -void ListBoxX::Create(Window &parent_, int ctrlID_, Point location_, int lineHeight_, bool unicodeMode_, int technology_) noexcept { +void ListBoxX::Create(Window &parent_, int ctrlID_, Point location_, int lineHeight_, bool unicodeMode_, int technology_) { parent = &parent_; ctrlID = ctrlID_; location = location_; @@ -2685,56 +3004,40 @@ void ListBoxX::Create(Window &parent_, int ctrlID_, Point location_, int lineHei HINSTANCE hinstanceParent = GetWindowInstance(hwndParent); // Window created as popup so not clipped within parent client area wid = ::CreateWindowEx( - WS_EX_WINDOWEDGE, ListBoxX_ClassName, L"", -#if LISTBOXX_USE_THICKFRAME + WS_EX_WINDOWEDGE, ListBoxX_ClassName, TEXT(""), WS_POPUP | WS_THICKFRAME, -#elif LISTBOXX_USE_BORDER - WS_POPUP | WS_BORDER, -#else - WS_POPUP, -#endif - 100, 100, 150, 80, hwndParent, - {}, + 100,100, 150,80, hwndParent, + NULL, hinstanceParent, this); - dpi = GetWindowDPI(hwndParent); + dpi = DpiForWindow(hwndParent); POINT locationw = POINTFromPoint(location); - ::MapWindowPoints(hwndParent, {}, &locationw, 1); + ::MapWindowPoints(hwndParent, NULL, &locationw, 1); location = PointFromPOINT(locationw); } -void ListBoxX::SetFont(const Font &font) noexcept { - if (font.GetID()) { +void ListBoxX::SetFont(const Font *font) { + const FontWin *pfm = dynamic_cast(font); + if (pfm) { if (fontCopy) { ::DeleteObject(fontCopy); - fontCopy = {}; + fontCopy = 0; } - const FormatAndMetrics *pfm = static_cast(font.GetID()); fontCopy = pfm->HFont(); - SetWindowFont(lb, fontCopy, FALSE); + SetWindowFont(lb, fontCopy, 0); } } -void ListBoxX::SetColour(ColourDesired fore, ColourDesired back) noexcept { - if (hbrBackground) { - ::DeleteObject(hbrBackground); - hbrBackground = {}; - } - colorText = fore.AsInteger(); - colorBackground = back.AsInteger(); - hbrBackground = ::CreateSolidBrush(colorBackground); -} - -void ListBoxX::SetAverageCharWidth(int width) noexcept { +void ListBoxX::SetAverageCharWidth(int width) { aveCharWidth = width; } -void ListBoxX::SetVisibleRows(int rows) noexcept { +void ListBoxX::SetVisibleRows(int rows) { desiredVisibleRows = rows; } -int ListBoxX::GetVisibleRows() const noexcept { +int ListBoxX::GetVisibleRows() const { return desiredVisibleRows; } @@ -2753,18 +3056,17 @@ PRectangle ListBoxX::GetDesiredRect() { int width = MinClientWidth(); HDC hdc = ::GetDC(lb); HFONT oldFont = SelectFont(hdc, fontCopy); - SIZE textSize = { 0, 0 }; + SIZE textSize = {0, 0}; int len = 0; if (widestItem) { len = static_cast(strlen(widestItem)); if (unicodeMode) { - const TextWide tbuf(widestItem, unicodeMode); + const TextWide tbuf(widestItem, SC_CP_UTF8); ::GetTextExtentPoint32W(hdc, tbuf.buffer, tbuf.tlen, &textSize); } else { ::GetTextExtentPoint32A(hdc, widestItem, len, &textSize); } } - TEXTMETRIC tm; ::GetTextMetrics(hdc, &tm); maxCharWidth = tm.tmMaxCharWidth; @@ -2776,11 +3078,10 @@ PRectangle ListBoxX::GetDesiredRect() { width = widthDesired; rcDesired.right = rcDesired.left + TextOffset() + width + (TextInset.x * 2); - if (Length() > rows) { - rcDesired.right += SystemMetricsForDpi(SM_CXVSCROLL, dpi.x); - } + if (Length() > rows) + rcDesired.right += SystemMetricsForDpi(SM_CXVSCROLL, dpi); - AdjustWindowRect(&rcDesired, dpi.y); + AdjustWindowRect(&rcDesired, dpi); return rcDesired; } @@ -2789,9 +3090,9 @@ int ListBoxX::TextOffset() const { return static_cast(pixWidth == 0 ? ItemInset.x : ItemInset.x + pixWidth + (ImageInset.x * 2)); } -int ListBoxX::CaretFromEdge() const { +int ListBoxX::CaretFromEdge() { PRectangle rc; - AdjustWindowRect(&rc, dpi.y); + AdjustWindowRect(&rc, dpi); return TextOffset() + static_cast(TextInset.x + (0 - rc.left) - 1); } @@ -2802,12 +3103,12 @@ void ListBoxX::Clear() noexcept { lti.Clear(); } -void ListBoxX::Append(const char *, int) const noexcept { +void ListBoxX::Append(char *, int) { // This method is no longer called in Scintilla PLATFORM_ASSERT(false); } -int ListBoxX::Length() const noexcept { +int ListBoxX::Length() { return lti.Count(); } @@ -2822,35 +3123,52 @@ void ListBoxX::Select(int n) { SetRedraw(true); } -int ListBoxX::GetSelection() const noexcept { +int ListBoxX::GetSelection() { return ListBox_GetCurSel(lb); } // This is not actually called at present -int ListBoxX::Find(const char *) const noexcept { +int ListBoxX::Find(const char *) { return LB_ERR; } -void ListBoxX::GetValue(int n, char *value, int len) const noexcept { +std::string ListBoxX::GetValue(int n) { const ListItemData item = lti.Get(n); - strncpy_s(value, len, item.text, len); - value[len - 1] = '\0'; + return item.text; } void ListBoxX::RegisterImage(int type, const char *xpm_data) { XPM xpmImage(xpm_data); - images.Add(type, new RGBAImage(xpmImage)); + images.AddImage(type, std::make_unique(xpmImage)); } void ListBoxX::RegisterRGBAImage(int type, int width, int height, const unsigned char *pixelsImage) { - images.Add(type, new RGBAImage(width, height, 1.0, pixelsImage)); + images.AddImage(type, std::make_unique(width, height, 1.0f, pixelsImage)); } -void ListBoxX::ClearRegisteredImages() noexcept { +void ListBoxX::ClearRegisteredImages() { images.Clear(); } -void ListBoxX::Draw(const DRAWITEMSTRUCT *pDrawItem) { +namespace { + +int ColourOfElement(std::optional colour, int nIndex) { + if (colour.has_value()) { + return colour.value().GetColour().AsInteger(); + } else { + return ::GetSysColor(nIndex); + } +} + +void FillRectColour(HDC hdc, const RECT *lprc, int colour) noexcept { + const HBRUSH brush = ::CreateSolidBrush(colour); + ::FillRect(hdc, lprc, brush); + ::DeleteObject(brush); +} + +} + +void ListBoxX::Draw(DRAWITEMSTRUCT *pDrawItem) { if ((pDrawItem->itemAction == ODA_SELECT) || (pDrawItem->itemAction == ODA_DRAWENTIRE)) { RECT rcBox = pDrawItem->rcItem; rcBox.left += TextOffset(); @@ -2858,14 +3176,14 @@ void ListBoxX::Draw(const DRAWITEMSTRUCT *pDrawItem) { RECT rcImage = pDrawItem->rcItem; rcImage.right = rcBox.left; // The image is not highlighted - ::FillRect(pDrawItem->hDC, &rcImage, hbrBackground); - ::FillRect(pDrawItem->hDC, &rcBox, reinterpret_cast(COLOR_HIGHLIGHT + 1)); - ::SetBkColor(pDrawItem->hDC, ::GetSysColor(COLOR_HIGHLIGHT)); - ::SetTextColor(pDrawItem->hDC, ::GetSysColor(COLOR_HIGHLIGHTTEXT)); + FillRectColour(pDrawItem->hDC, &rcImage, ColourOfElement(options.back, COLOR_WINDOW)); + FillRectColour(pDrawItem->hDC, &rcBox, ColourOfElement(options.backSelected, COLOR_HIGHLIGHT)); + ::SetBkColor(pDrawItem->hDC, ColourOfElement(options.backSelected, COLOR_HIGHLIGHT)); + ::SetTextColor(pDrawItem->hDC, ColourOfElement(options.foreSelected, COLOR_HIGHLIGHTTEXT)); } else { - ::FillRect(pDrawItem->hDC, &pDrawItem->rcItem, hbrBackground); - ::SetBkColor(pDrawItem->hDC, colorBackground); - ::SetTextColor(pDrawItem->hDC, colorText); + FillRectColour(pDrawItem->hDC, &pDrawItem->rcItem, ColourOfElement(options.back, COLOR_WINDOW)); + ::SetBkColor(pDrawItem->hDC, ColourOfElement(options.back, COLOR_WINDOW)); + ::SetTextColor(pDrawItem->hDC, ColourOfElement(options.fore, COLOR_WINDOWTEXT)); } const ListItemData item = lti.Get(pDrawItem->itemID); @@ -2877,10 +3195,10 @@ void ListBoxX::Draw(const DRAWITEMSTRUCT *pDrawItem) { ::InsetRect(&rcText, static_cast(TextInset.x), static_cast(TextInset.y)); if (unicodeMode) { - const TextWide tbuf(text, unicodeMode); - ::DrawTextW(pDrawItem->hDC, tbuf.buffer, tbuf.tlen, &rcText, DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOCLIP); + const TextWide tbuf(text, SC_CP_UTF8); + ::DrawTextW(pDrawItem->hDC, tbuf.buffer, tbuf.tlen, &rcText, DT_NOPREFIX|DT_END_ELLIPSIS|DT_SINGLELINE|DT_NOCLIP); } else { - ::DrawTextA(pDrawItem->hDC, text, len, &rcText, DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOCLIP); + ::DrawTextA(pDrawItem->hDC, text, len, &rcText, DT_NOPREFIX|DT_END_ELLIPSIS|DT_SINGLELINE|DT_NOCLIP); } // Draw the image, if any @@ -2906,7 +3224,7 @@ void ListBoxX::Draw(const DRAWITEMSTRUCT *pDrawItem) { 0, D2D1_RENDER_TARGET_USAGE_NONE, D2D1_FEATURE_LEVEL_DEFAULT - ); + ); ID2D1DCRenderTarget *pDCRT = nullptr; HRESULT hr = pD2DFactory->CreateDCRenderTarget(&props, &pDCRT); if (SUCCEEDED(hr) && pDCRT) { @@ -2922,9 +3240,9 @@ void ListBoxX::Draw(const DRAWITEMSTRUCT *pDrawItem) { surfaceItem->DrawRGBAImage(rcImage, pimage->GetWidth(), pimage->GetHeight(), pimage->Pixels()); pDCRT->EndDraw(); + ReleaseUnknown(pDCRT); } } - ReleaseUnknown(pDCRT); #endif } } @@ -2949,20 +3267,20 @@ void ListBoxX::AppendListItem(const char *text, const char *numword) { } } -void ListBoxX::SetDelegate(IListBoxDelegate *lbDelegate) noexcept { +void ListBoxX::SetDelegate(IListBoxDelegate *lbDelegate) { delegate = lbDelegate; } -void ListBoxX::SetList(const char *list, const char separator, const char typesep) { +void ListBoxX::SetList(const char *list, char separator, char typesep) { // Turn off redraw while populating the list - this has a significant effect, even if // the listbox is not visible. SetRedraw(false); Clear(); const size_t size = strlen(list); - char *words = lti.SetWords(list, size); + char *words = lti.SetWords(list); char *startword = words; char *numword = nullptr; - for (size_t i = 0; i < size; i++) { + for (size_t i=0; i < size; i++) { if (words[i] == separator) { words[i] = '\0'; if (numword) @@ -2983,25 +3301,24 @@ void ListBoxX::SetList(const char *list, const char separator, const char typese // Finally populate the listbox itself with the correct number of items const int count = lti.Count(); ::SendMessage(lb, LB_INITSTORAGE, count, 0); - for (intptr_t j = 0; j < count; j++) { - ListBox_AddItemData(lb, j + 1); + for (intptr_t j=0; jInflate(ListBoxXFakeFrameSize, ListBoxXFakeFrameSize); -#endif } int ListBoxX::ItemHeight() const { @@ -3014,24 +3331,24 @@ int ListBoxX::ItemHeight() const { } int ListBoxX::MinClientWidth() const noexcept { - return 12 * (aveCharWidth + aveCharWidth / 3); + return 12 * (aveCharWidth+aveCharWidth/3); } POINT ListBoxX::MinTrackSize() const { PRectangle rc = PRectangle::FromInts(0, 0, MinClientWidth(), ItemHeight()); - AdjustWindowRect(&rc, dpi.y); - POINT ret = { static_cast(rc.Width()), static_cast(rc.Height()) }; + AdjustWindowRect(&rc, dpi); + POINT ret = {static_cast(rc.Width()), static_cast(rc.Height())}; return ret; } POINT ListBoxX::MaxTrackSize() const { - const int width = maxCharWidth * maxItemCharacters + static_cast(TextInset.x) * 2 + - TextOffset() + SystemMetricsForDpi(SM_CXVSCROLL, dpi.x); PRectangle rc = PRectangle::FromInts(0, 0, - std::max(MinClientWidth(), width), + std::max(static_cast(MinClientWidth()), + maxCharWidth * maxItemCharacters + static_cast(TextInset.x) * 2 + + TextOffset() + SystemMetricsForDpi(SM_CXVSCROLL, dpi)), ItemHeight() * lti.Count()); - AdjustWindowRect(&rc, dpi.y); - POINT ret = { static_cast(rc.Width()), static_cast(rc.Height()) }; + AdjustWindowRect(&rc, dpi); + POINT ret = {static_cast(rc.Width()), static_cast(rc.Height())}; return ret; } @@ -3048,34 +3365,36 @@ void ListBoxX::ResizeToCursor() { const Point pt = PointFromPOINT(ptw) + dragOffset; switch (resizeHit) { - case HTLEFT: - rc.left = pt.x; - break; - case HTRIGHT: - rc.right = pt.x; - break; - case HTTOP: - rc.top = pt.y; - break; - case HTTOPLEFT: - rc.top = pt.y; - rc.left = pt.x; - break; - case HTTOPRIGHT: - rc.top = pt.y; - rc.right = pt.x; - break; - case HTBOTTOM: - rc.bottom = pt.y; - break; - case HTBOTTOMLEFT: - rc.bottom = pt.y; - rc.left = pt.x; - break; - case HTBOTTOMRIGHT: - rc.bottom = pt.y; - rc.right = pt.x; - break; + case HTLEFT: + rc.left = pt.x; + break; + case HTRIGHT: + rc.right = pt.x; + break; + case HTTOP: + rc.top = pt.y; + break; + case HTTOPLEFT: + rc.top = pt.y; + rc.left = pt.x; + break; + case HTTOPRIGHT: + rc.top = pt.y; + rc.right = pt.x; + break; + case HTBOTTOM: + rc.bottom = pt.y; + break; + case HTBOTTOMLEFT: + rc.bottom = pt.y; + rc.left = pt.x; + break; + case HTBOTTOMRIGHT: + rc.bottom = pt.y; + rc.right = pt.x; + break; + default: + break; } const POINT ptMin = MinTrackSize(); @@ -3089,46 +3408,46 @@ void ListBoxX::ResizeToCursor() { SetPosition(rc); } -void ListBoxX::StartResize(WPARAM hitCode) noexcept { +void ListBoxX::StartResize(WPARAM hitCode) { rcPreSize = GetPosition(); POINT cursorPos; ::GetCursorPos(&cursorPos); switch (hitCode) { - case HTRIGHT: - case HTBOTTOM: - case HTBOTTOMRIGHT: - dragOffset.x = rcPreSize.right - cursorPos.x; - dragOffset.y = rcPreSize.bottom - cursorPos.y; - break; + case HTRIGHT: + case HTBOTTOM: + case HTBOTTOMRIGHT: + dragOffset.x = rcPreSize.right - cursorPos.x; + dragOffset.y = rcPreSize.bottom - cursorPos.y; + break; - case HTTOPRIGHT: - dragOffset.x = rcPreSize.right - cursorPos.x; - dragOffset.y = rcPreSize.top - cursorPos.y; - break; + case HTTOPRIGHT: + dragOffset.x = rcPreSize.right - cursorPos.x; + dragOffset.y = rcPreSize.top - cursorPos.y; + break; // Note that the current hit test code prevents the left edge cases ever firing // as we don't want the left edge to be movable - case HTLEFT: - case HTTOP: - case HTTOPLEFT: - dragOffset.x = rcPreSize.left - cursorPos.x; - dragOffset.y = rcPreSize.top - cursorPos.y; - break; - case HTBOTTOMLEFT: - dragOffset.x = rcPreSize.left - cursorPos.x; - dragOffset.y = rcPreSize.bottom - cursorPos.y; - break; + case HTLEFT: + case HTTOP: + case HTTOPLEFT: + dragOffset.x = rcPreSize.left - cursorPos.x; + dragOffset.y = rcPreSize.top - cursorPos.y; + break; + case HTBOTTOMLEFT: + dragOffset.x = rcPreSize.left - cursorPos.x; + dragOffset.y = rcPreSize.bottom - cursorPos.y; + break; - default: - return; + default: + return; } ::SetCapture(GetHWND()); resizeHit = hitCode; } -LRESULT ListBoxX::NcHitTest(WPARAM wParam, LPARAM lParam) const noexcept { +LRESULT ListBoxX::NcHitTest(WPARAM wParam, LPARAM lParam) const { const PRectangle rc = GetPosition(); LRESULT hit = ::DefWindowProc(GetHWND(), WM_NCHITTEST, wParam, lParam); @@ -3137,65 +3456,39 @@ LRESULT ListBoxX::NcHitTest(WPARAM wParam, LPARAM lParam) const noexcept { // window caption height + frame, even if one is hovering over the bottom edge of // the frame, so workaround that here if (hit >= HTTOP && hit <= HTTOPRIGHT) { - const int minHeight = SystemMetricsForDpi(SM_CYMINTRACK, dpi.y); + const int minHeight = SystemMetricsForDpi(SM_CYMINTRACK, dpi); const int yPos = GET_Y_LPARAM(lParam); - if ((rc.Height() < minHeight) && (yPos > ((rc.top + rc.bottom) / 2))) { + if ((rc.Height() < minHeight) && (yPos > ((rc.top + rc.bottom)/2))) { hit += HTBOTTOM - HTTOP; } } -#if LISTBOXX_USE_BORDER || LISTBOXX_USE_FAKE_FRAME - else if (hit < HTSIZEFIRST || hit > HTSIZELAST) { - const int cx = SystemMetricsForDpi(SM_CXVSCROLL, dpi.x); -#if LISTBOXX_USE_BORDER - const PRectangle rcInner = rc.Deflate(SystemMetricsForDpi(SM_CXBORDER, dpi.x), SystemMetricsForDpi(SM_CYBORDER, dpi.y)); -#else - const PRectangle rcInner = rc.Deflate(ListBoxXFakeFrameSize, ListBoxXFakeFrameSize); -#endif - const int xPos = GET_X_LPARAM(lParam); - const int yPos = GET_Y_LPARAM(lParam); - /* - 13 | 12 | 14 4 | 3 | 5 - 10 | | 11 => 1 | 0 | 2 - 16 | 15 | 17 7 | 6 | 8 - */ - const int x = (xPos <= rcInner.left) ? 1 : ((xPos >= rcInner.right - cx) ? 2 : 0); - int y = (yPos <= rcInner.top) ? 3 : ((yPos >= rcInner.bottom) ? 6 : 0); - if (y == 0 && x == 2) { - if (location.y < rc.top) { - y = (yPos >= rcInner.bottom - cx) ? 6 : 0; - } else { - y = (yPos <= rcInner.top + cx) ? 3 : 0; - } - } - const int h = x + y; - hit = h ? (9 + h) : HTERROR; - } -#endif // Never permit resizing that moves the left edge. Allow movement of top or bottom edge // depending on whether the list is above or below the caret switch (hit) { - case HTLEFT: - case HTTOPLEFT: - case HTBOTTOMLEFT: - hit = HTERROR; - break; - - case HTTOP: - case HTTOPRIGHT: { - // Valid only if caret below list - if (location.y < rc.top) + case HTLEFT: + case HTTOPLEFT: + case HTBOTTOMLEFT: hit = HTERROR; - } - break; + break; - case HTBOTTOM: - case HTBOTTOMRIGHT: { - // Valid only if caret above list - if (rc.bottom <= location.y) - hit = HTERROR; - } - break; + case HTTOP: + case HTTOPRIGHT: { + // Valid only if caret below list + if (location.y < rc.top) + hit = HTERROR; + } + break; + + case HTBOTTOM: + case HTBOTTOMRIGHT: { + // Valid only if caret above list + if (rc.bottom <= location.y) + hit = HTERROR; + } + break; + default: + break; } return hit; @@ -3218,7 +3511,7 @@ void ListBoxX::OnSelChange() { POINT ListBoxX::GetClientExtent() const noexcept { RECT rc; ::GetWindowRect(HwndFromWindowID(wid), &rc); - POINT ret{ rc.right - rc.left, rc.bottom - rc.top }; + POINT ret { rc.right - rc.left, rc.bottom - rc.top }; return ret; } @@ -3226,7 +3519,7 @@ void ListBoxX::CentreItem(int n) { // If below mid point, scroll up to centre, but with more items below if uneven if (n >= 0) { const POINT extent = GetClientExtent(); - const int visible = extent.y / ItemHeight(); + const int visible = extent.y/ItemHeight(); if (visible < Length()) { const int top = ListBox_GetTopIndex(lb); const int half = (visible - 1) / 2; @@ -3237,7 +3530,7 @@ void ListBoxX::CentreItem(int n) { } // Performs a double-buffered paint operation to avoid flicker -void ListBoxX::Paint(HDC hDC) noexcept { +void ListBoxX::Paint(HDC hDC) { const POINT extent = GetClientExtent(); HBITMAP hBitmap = ::CreateCompatibleBitmap(hDC, extent.x, extent.y); HDC bitmapDC = ::CreateCompatibleDC(hDC); @@ -3246,9 +3539,9 @@ void ListBoxX::Paint(HDC hDC) noexcept { // unpainted area when at the end of a non-integrally sized list with a // vertical scroll bar const RECT rc = { 0, 0, extent.x, extent.y }; - ::FillRect(bitmapDC, &rc, hbrBackground); + FillRectColour(bitmapDC, &rc, ColourOfElement(options.back, COLOR_WINDOWTEXT)); // Paint the entire client area and vertical scrollbar - ::SendMessage(lb, WM_PRINT, reinterpret_cast(bitmapDC), PRF_CLIENT | PRF_NONCLIENT); + ::SendMessage(lb, WM_PRINT, reinterpret_cast(bitmapDC), PRF_CLIENT|PRF_NONCLIENT); ::BitBlt(hDC, 0, 0, extent.x, extent.y, bitmapDC, 0, 0, SRCCOPY); // Select a stock brush to prevent warnings from BoundsChecker SelectBrush(bitmapDC, GetStockBrush(WHITE_BRUSH)); @@ -3257,7 +3550,7 @@ void ListBoxX::Paint(HDC hDC) noexcept { ::DeleteObject(hBitmap); } -LRESULT CALLBACK ListBoxX::ControlWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR /*dwRefData*/) { +LRESULT PASCAL ListBoxX::ControlWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { try { ListBoxX *lbx = static_cast(PointerFromWindow(::GetParent(hWnd))); switch (iMessage) { @@ -3265,78 +3558,85 @@ LRESULT CALLBACK ListBoxX::ControlWndProc(HWND hWnd, UINT iMessage, WPARAM wPara return TRUE; case WM_PAINT: { - PAINTSTRUCT ps; - HDC hDC = ::BeginPaint(hWnd, &ps); - if (lbx) { - lbx->Paint(hDC); + PAINTSTRUCT ps; + HDC hDC = ::BeginPaint(hWnd, &ps); + if (lbx) { + lbx->Paint(hDC); + } + ::EndPaint(hWnd, &ps); } - ::EndPaint(hWnd, &ps); - } - return 0; + return 0; case WM_MOUSEACTIVATE: // This prevents the view activating when the scrollbar is clicked return MA_NOACTIVATE; case WM_LBUTTONDOWN: { - // We must take control of selection to prevent the ListBox activating - // the popup - const LRESULT lResult = ::SendMessage(hWnd, LB_ITEMFROMPOINT, 0, lParam); - const int item = LOWORD(lResult); - if (HIWORD(lResult) == 0 && item >= 0) { - ListBox_SetCurSel(hWnd, item); - if (lbx) { - lbx->OnSelChange(); + // We must take control of selection to prevent the ListBox activating + // the popup + const LRESULT lResult = ::SendMessage(hWnd, LB_ITEMFROMPOINT, 0, lParam); + const int item = LOWORD(lResult); + if (HIWORD(lResult) == 0 && item >= 0) { + ListBox_SetCurSel(hWnd, item); + if (lbx) { + lbx->OnSelChange(); + } } } - } - return 0; + return 0; case WM_LBUTTONUP: return 0; case WM_LBUTTONDBLCLK: { - if (lbx) { - lbx->OnDoubleClick(); + if (lbx) { + lbx->OnDoubleClick(); + } } - } - return 0; + return 0; case WM_MBUTTONDOWN: // disable the scroll wheel button click action return 0; - case WM_NCDESTROY: - RemoveWindowSubclass(hWnd, ControlWndProc, uIdSubclass); + default: break; } + + WNDPROC prevWndProc = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); + if (prevWndProc) { + return ::CallWindowProc(prevWndProc, hWnd, iMessage, wParam, lParam); + } else { + return ::DefWindowProc(hWnd, iMessage, wParam, lParam); + } } catch (...) { } - return ::DefSubclassProc(hWnd, iMessage, wParam, lParam); + return ::DefWindowProc(hWnd, iMessage, wParam, lParam); } LRESULT ListBoxX::WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { switch (iMessage) { case WM_CREATE: { - HINSTANCE hinstanceParent = GetWindowInstance(HwndFromWindow(*parent)); - // Note that LBS_NOINTEGRALHEIGHT is specified to fix cosmetic issue when resizing the list - // but has useful side effect of speeding up list population significantly - lb = ::CreateWindowEx( - 0, L"listbox", L"", - WS_CHILD | WS_VSCROLL | WS_VISIBLE | - LBS_OWNERDRAWFIXED | LBS_NODATA | LBS_NOINTEGRALHEIGHT, - 0, 0, 150, 80, hWnd, - reinterpret_cast(static_cast(ctrlID)), - hinstanceParent, - nullptr); - ::SetWindowSubclass(lb, ControlWndProc, 0, 0); - } - break; + HINSTANCE hinstanceParent = GetWindowInstance(HwndFromWindow(*parent)); + // Note that LBS_NOINTEGRALHEIGHT is specified to fix cosmetic issue when resizing the list + // but has useful side effect of speeding up list population significantly + lb = ::CreateWindowEx( + 0, TEXT("listbox"), TEXT(""), + WS_CHILD | WS_VSCROLL | WS_VISIBLE | + LBS_OWNERDRAWFIXED | LBS_NODATA | LBS_NOINTEGRALHEIGHT, + 0, 0, 150,80, hWnd, + reinterpret_cast(static_cast(ctrlID)), + hinstanceParent, + 0); + WNDPROC prevWndProc = SubclassWindow(lb, ControlWndProc); + ::SetWindowLongPtr(lb, GWLP_USERDATA, reinterpret_cast(prevWndProc)); + } + break; case WM_SIZE: if (lb) { SetRedraw(false); - ::SetWindowPos(lb, nullptr, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE); + ::SetWindowPos(lb, 0, 0,0, LOWORD(lParam), HIWORD(lParam), SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE); // Ensure the selection remains visible CentreItem(GetSelection()); SetRedraw(true); @@ -3344,11 +3644,11 @@ LRESULT ListBoxX::WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam break; case WM_PAINT: { - PAINTSTRUCT ps; - ::BeginPaint(hWnd, &ps); - ::EndPaint(hWnd, &ps); - } - break; + PAINTSTRUCT ps; + ::BeginPaint(hWnd, &ps); + ::EndPaint(hWnd, &ps); + } + break; case WM_COMMAND: // This is not actually needed now - the registered double click action is used @@ -3357,17 +3657,17 @@ LRESULT ListBoxX::WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam break; case WM_MEASUREITEM: { - MEASUREITEMSTRUCT *pMeasureItem = reinterpret_cast(lParam); - pMeasureItem->itemHeight = ItemHeight(); - } - break; + MEASUREITEMSTRUCT *pMeasureItem = reinterpret_cast(lParam); + pMeasureItem->itemHeight = ItemHeight(); + } + break; case WM_DRAWITEM: Draw(reinterpret_cast(lParam)); break; case WM_DESTROY: - lb = nullptr; + lb = 0; SetWindowPointer(hWnd, nullptr); return ::DefWindowProc(hWnd, iMessage, wParam, lParam); @@ -3377,65 +3677,15 @@ LRESULT ListBoxX::WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam return TRUE; case WM_GETMINMAXINFO: { - MINMAXINFO *minMax = reinterpret_cast(lParam); - minMax->ptMaxTrackSize = MaxTrackSize(); - minMax->ptMinTrackSize = MinTrackSize(); - } - break; + MINMAXINFO *minMax = reinterpret_cast(lParam); + minMax->ptMaxTrackSize = MaxTrackSize(); + minMax->ptMinTrackSize = MinTrackSize(); + } + break; case WM_MOUSEACTIVATE: return MA_NOACTIVATE; -#if LISTBOXX_USE_FAKE_FRAME - case WM_NCPAINT: { - HDC hDC = ::GetWindowDC(hWnd); - RECT rect; - ::GetClientRect(hWnd, &rect); - - // outer frame - rect.right += 2*ListBoxXFakeFrameSize; - rect.bottom += 2*ListBoxXFakeFrameSize; - const int width = rect.right - rect.left; - const int height = rect.bottom - rect.top; - - // inner border - RECT client = rect; - ::InflateRect(&client, -ListBoxXFakeFrameSize + 1, -ListBoxXFakeFrameSize + 1); - - HDC hMemDC = CreateCompatibleDC(hDC); - const BITMAPINFO bpih = { {sizeof(BITMAPINFOHEADER), width, height, 1, 32, BI_RGB, 0, 0, 0, 0, 0}, - {{0, 0, 0, 0}} }; - HBITMAP hbmMem = CreateDIBSection(hMemDC, &bpih, DIB_RGB_COLORS, nullptr, nullptr, 0); - - if (hbmMem) { - HBITMAP hbmOld = SelectBitmap(hMemDC, hbmMem); - BLENDFUNCTION merge = { AC_SRC_OVER, 0, 0, AC_SRC_ALPHA }; - - GdiAlphaBlend(hDC, rect.left, rect.top, width, height, hMemDC, 0, 0, width, height, merge); - - SelectBitmap(hMemDC, hbmOld); - ::DeleteObject(hbmMem); - } - ::DeleteDC(hMemDC); - - //HPEN hPen = ::CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_WINDOWFRAME)); - HPEN hPen = ::CreatePen(PS_SOLID, 1, RGB(255, 0, 0)); - HPEN hPenOld = SelectPen(hDC, hPen); - ::Rectangle(hDC, client.left, client.top, client.right, client.bottom); - ::SelectObject(hDC, hPenOld); - ::DeleteObject(hPen); - - ::ReleaseDC(hWnd, hDC); - return 0; - } - - case WM_NCCALCSIZE: { - LPRECT rect = reinterpret_cast(lParam); - ::InflateRect(rect, -ListBoxXFakeFrameSize, -ListBoxXFakeFrameSize); - return 0; - } -#endif - case WM_NCHITTEST: return NcHitTest(wParam, lParam); @@ -3446,13 +3696,13 @@ LRESULT ListBoxX::WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam return 0; case WM_MOUSEMOVE: { - if (resizeHit == 0) { - return ::DefWindowProc(hWnd, iMessage, wParam, lParam); - } else { - ResizeToCursor(); + if (resizeHit == 0) { + return ::DefWindowProc(hWnd, iMessage, wParam, lParam); + } else { + ResizeToCursor(); + } } - } - break; + break; case WM_LBUTTONUP: case WM_CANCELMODE: @@ -3461,12 +3711,17 @@ LRESULT ListBoxX::WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam ::ReleaseCapture(); } return ::DefWindowProc(hWnd, iMessage, wParam, lParam); - case WM_MOUSEWHEEL: wheelDelta -= GET_WHEEL_DELTA_WPARAM(wParam); if (std::abs(wheelDelta) >= WHEEL_DELTA) { const int nRows = GetVisibleRows(); - int linesToScroll = std::clamp(nRows - 1, 1, 3); + int linesToScroll = 1; + if (nRows > 1) { + linesToScroll = nRows - 1; + } + if (linesToScroll > 3) { + linesToScroll = 3; + } linesToScroll *= (wheelDelta / WHEEL_DELTA); int top = ListBox_GetTopIndex(lb) + linesToScroll; if (top < 0) { @@ -3477,7 +3732,7 @@ LRESULT ListBoxX::WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam if (wheelDelta >= 0) wheelDelta = wheelDelta % WHEEL_DELTA; else - wheelDelta = -(-wheelDelta % WHEEL_DELTA); + wheelDelta = - (-wheelDelta % WHEEL_DELTA); } break; @@ -3488,8 +3743,8 @@ LRESULT ListBoxX::WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam return 0; } -LRESULT CALLBACK ListBoxX::StaticWndProc( - HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { +LRESULT PASCAL ListBoxX::StaticWndProc( + HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { if (iMessage == WM_CREATE) { CREATESTRUCT *pCreate = reinterpret_cast(lParam); SetWindowPointer(hWnd, pCreate->lpCreateParams); @@ -3515,7 +3770,7 @@ bool ListBoxX_Register() noexcept { wndclassc.cbWndExtra = sizeof(ListBoxX *); wndclassc.hInstance = hinstPlatformRes; wndclassc.lpfnWndProc = ListBoxX::StaticWndProc; - wndclassc.hCursor = ::LoadCursor({}, IDC_ARROW); + wndclassc.hCursor = ::LoadCursor(NULL, IDC_ARROW); wndclassc.lpszClassName = ListBoxX_ClassName; return ::RegisterClassEx(&wndclassc) != 0; @@ -3532,7 +3787,7 @@ void ListBoxX_Unregister() noexcept { Menu::Menu() noexcept : mid{} { } -void Menu::CreatePopUp() noexcept { +void Menu::CreatePopUp() { Destroy(); mid = ::CreatePopupMenu(); } @@ -3540,91 +3795,48 @@ void Menu::CreatePopUp() noexcept { void Menu::Destroy() noexcept { if (mid) ::DestroyMenu(static_cast(mid)); - mid = nullptr; + mid = 0; } -void Menu::Show(Point pt, const Window &w) noexcept { +void Menu::Show(Point pt, const Window &w) { ::TrackPopupMenu(static_cast(mid), TPM_RIGHTBUTTON, static_cast(pt.x - 4), static_cast(pt.y), 0, HwndFromWindow(w), nullptr); Destroy(); } -class DynamicLibraryImpl : public DynamicLibrary { -protected: - HMODULE h; -public: - explicit DynamicLibraryImpl(const char* modulePath) noexcept { - h = ::LoadLibraryA(modulePath); - } - - ~DynamicLibraryImpl() override { - if (h) - ::FreeLibrary(h); - } - - // Use GetProcAddress to get a pointer to the relevant function. - Function FindFunction(const char* name) noexcept override { - if (h) { - // C++ standard doesn't like casts between function pointers and void pointers so use a union - union { - FARPROC fp; - Function f; - } fnConv; - fnConv.fp = ::GetProcAddress(h, name); - return fnConv.f; - } - else { - return nullptr; - } - } - - bool IsValid() noexcept override { - return h != nullptr; - } -}; - -DynamicLibrary* DynamicLibrary::Load(const char* modulePath) { - return static_cast(new DynamicLibraryImpl(modulePath)); -} - -ColourDesired Platform::Chrome() noexcept { +ColourDesired Platform::Chrome() { return ColourDesired(::GetSysColor(COLOR_3DFACE)); } -ColourDesired Platform::ChromeHighlight() noexcept { +ColourDesired Platform::ChromeHighlight() { return ColourDesired(::GetSysColor(COLOR_3DHIGHLIGHT)); } -const char *Platform::DefaultFont() noexcept { +const char *Platform::DefaultFont() { return "Verdana"; } -int Platform::DefaultFontSize() noexcept { - return 10; +int Platform::DefaultFontSize() { + return 8; } -unsigned int Platform::DoubleClickTime() noexcept { +unsigned int Platform::DoubleClickTime() { return ::GetDoubleClickTime(); } -//#define TRACE - -#ifdef TRACE void Platform::DebugDisplay(const char *s) noexcept { ::OutputDebugStringA(s); } -#else -void Platform::DebugDisplay(const char *) noexcept { -} -#endif + +//#define TRACE #ifdef TRACE void Platform::DebugPrintf(const char *format, ...) noexcept { char buffer[2000]; va_list pArguments; va_start(pArguments, format); - vsprintf(buffer, format, pArguments); + vsprintf(buffer,format,pArguments); va_end(pArguments); Platform::DebugDisplay(buffer); } @@ -3633,7 +3845,6 @@ void Platform::DebugPrintf(const char *, ...) noexcept { } #endif -#ifdef TRACE static bool assertionPopUps = true; bool Platform::ShowAssertionPopUps(bool assertionPopUps_) noexcept { @@ -3641,19 +3852,13 @@ bool Platform::ShowAssertionPopUps(bool assertionPopUps_) noexcept { assertionPopUps = assertionPopUps_; return ret; } -#else -bool Platform::ShowAssertionPopUps(bool) noexcept { - return false; -} -#endif -#ifdef TRACE void Platform::Assert(const char *c, const char *file, int line) noexcept { - char buffer[2000]{}; + char buffer[2000] {}; sprintf(buffer, "Assertion [%s] failed at %s %d%s", c, file, line, assertionPopUps ? "" : "\r\n"); if (assertionPopUps) { - const int idButton = ::MessageBoxA({}, buffer, "Assertion failure", - MB_ABORTRETRYIGNORE | MB_ICONHAND | MB_SETFOREGROUND | MB_TASKMODAL); + const int idButton = ::MessageBoxA(0, buffer, "Assertion failure", + MB_ABORTRETRYIGNORE|MB_ICONHAND|MB_SETFOREGROUND|MB_TASKMODAL); if (idButton == IDRETRY) { ::DebugBreak(); } else if (idButton == IDIGNORE) { @@ -3667,14 +3872,10 @@ void Platform::Assert(const char *c, const char *file, int line) noexcept { abort(); } } -#else -void Platform::Assert(const char *, const char *, int) noexcept { -} -#endif void Platform_Initialise(void *hInstance) noexcept { hinstPlatformRes = static_cast(hInstance); - //LoadDpiForWindow() is moved into wWinMain(). + LoadDpiForWindow(); ListBoxX_Register(); } @@ -3683,7 +3884,6 @@ void Platform_Finalise(bool fromDllMain) noexcept { if (!fromDllMain) { ReleaseUnknown(defaultRenderingParams); ReleaseUnknown(customClearTypeRenderingParams); - ReleaseUnknown(gdiInterop); ReleaseUnknown(pIDWriteFactory); ReleaseUnknown(pD2DFactory); if (hDLLDWrite) { @@ -3696,11 +3896,11 @@ void Platform_Finalise(bool fromDllMain) noexcept { } } #endif - if (!fromDllMain && hShcoreDLL) { - FreeLibrary(hShcoreDLL); - hShcoreDLL = {}; + if (!fromDllMain && hDLLShcore) { + FreeLibrary(hDLLShcore); + hDLLShcore = {}; } ListBoxX_Unregister(); } -} // namespace Scintilla +} diff --git a/scintilla/win32/PlatWin.h b/scintilla/win32/PlatWin.h index a5fdb441c..efcf57b94 100644 --- a/scintilla/win32/PlatWin.h +++ b/scintilla/win32/PlatWin.h @@ -4,60 +4,18 @@ **/ // Copyright 1998-2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. -#pragma once -// sdkddkver.h -#ifndef _WIN32_WINNT_VISTA -#define _WIN32_WINNT_VISTA 0x0600 -#endif -#ifndef _WIN32_WINNT_WIN7 -#define _WIN32_WINNT_WIN7 0x0601 -#endif -#ifndef _WIN32_WINNT_WIN8 -#define _WIN32_WINNT_WIN8 0x0602 -#endif -#ifndef _WIN32_WINNT_WINBLUE -#define _WIN32_WINNT_WINBLUE 0x0603 -#endif -#ifndef _WIN32_WINNT_WIN10 -#define _WIN32_WINNT_WIN10 0x0A00 -#endif +#ifndef PLATWIN_H +#define PLATWIN_H + +namespace Scintilla { #ifndef USER_DEFAULT_SCREEN_DPI #define USER_DEFAULT_SCREEN_DPI 96 #endif -#if !defined(DISABLE_D2D) -#define USE_D2D 1 -#endif - -#if defined(USE_D2D) -#if defined(_MSC_BUILD) && (VER_PRODUCTVERSION_W <= _WIN32_WINNT_WIN7) -#pragma warning(push) -#pragma warning(disable: 4458) -// d2d1helper.h(677,19): warning C4458: declaration of 'a' hides class member -#endif -#include -#include -#if defined(_MSC_BUILD) && (VER_PRODUCTVERSION_W <= _WIN32_WINNT_WIN7) -#pragma warning(pop) -#endif -#endif - -#ifdef __cplusplus -DPI_T GetWindowDPI(HWND hwnd); -int SystemMetricsForDpi(int nIndex, unsigned dpi); -BOOL AdjustWindowRectForDpi(LPRECT lpRect, DWORD dwStyle, DWORD dwExStyle, unsigned dpi); -#else -extern "C" DPI_T GetWindowDPI(HWND hwnd); -extern "C" int SystemMetricsForDpi(int nIndex, unsigned dpi); -extern "C" BOOL AdjustWindowRectForDpi(LPRECT lpRect, DWORD dwStyle, DWORD dwExStyle, unsigned dpi); -#endif // !__cplusplus - - -namespace Scintilla { - extern void Platform_Initialise(void *hInstance) noexcept; + extern void Platform_Finalise(bool fromDllMain) noexcept; constexpr RECT RectFromPRectangle(PRectangle prc) noexcept { @@ -67,7 +25,7 @@ constexpr RECT RectFromPRectangle(PRectangle prc) noexcept { } constexpr POINT POINTFromPoint(Point pt) noexcept { - return POINT { static_cast(pt.x), static_cast(pt.y) }; + return POINT{ static_cast(pt.x), static_cast(pt.y) }; } constexpr Point PointFromPOINT(POINT pt) noexcept { @@ -82,21 +40,13 @@ inline HWND HwndFromWindow(const Window &w) noexcept { return HwndFromWindowID(w.GetID()); } -inline void *PointerFromWindow(HWND hWnd) noexcept { - return reinterpret_cast(::GetWindowLongPtr(hWnd, 0)); -} - -inline void SetWindowPointer(HWND hWnd, void *ptr) noexcept { - ::SetWindowLongPtr(hWnd, 0, reinterpret_cast(ptr)); -} +void *PointerFromWindow(HWND hWnd) noexcept; +void SetWindowPointer(HWND hWnd, void *ptr) noexcept; /// Find a function in a DLL and convert to a function pointer. /// This avoids undefined and conditionally defined behaviour. template -inline T DLLFunction(HMODULE hModule, LPCSTR lpProcName) noexcept { -#if 1 - return reinterpret_cast(::GetProcAddress(hModule, lpProcName)); -#else +T DLLFunction(HMODULE hModule, LPCSTR lpProcName) noexcept { if (!hModule) { return nullptr; } @@ -105,39 +55,44 @@ inline T DLLFunction(HMODULE hModule, LPCSTR lpProcName) noexcept { T fp; memcpy(&fp, &function, sizeof(T)); return fp; -#endif -} - -template -inline T DLLFunctionEx(LPCWSTR lpDllName, LPCSTR lpProcName) noexcept { - return DLLFunction(::GetModuleHandleW(lpDllName), lpProcName); } // Release an IUnknown* and set to nullptr. // While IUnknown::Release must be noexcept, it isn't marked as such so produces // warnings which are avoided by the catch. template -inline void ReleaseUnknown(T *&ppUnknown) noexcept { +void ReleaseUnknown(T *&ppUnknown) noexcept { if (ppUnknown) { try { ppUnknown->Release(); - } catch (...) { + } + catch (...) { // Never occurs } ppUnknown = nullptr; } } -inline UINT DpiYForWindow(WindowID wid) noexcept { - return GetWindowDPI(HwndFromWindowID(wid)).y; -} -HCURSOR LoadReverseArrowCursor(DPI_T dpi) noexcept; +UINT DpiForWindow(WindowID wid) noexcept; + +int SystemMetricsForDpi(int nIndex, UINT dpi) noexcept; + +// >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> +#ifndef AlphaBlend +#define AlphaBlend GdiAlphaBlend +#endif +BOOL AdjustWindowRectForDpi(LPRECT lpRect, DWORD dwStyle, DWORD dwExStyle, UINT dpi) noexcept; +// <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< + +HCURSOR LoadReverseArrowCursor(UINT dpi) noexcept; #if defined(USE_D2D) -extern bool LoadD2D() noexcept; +extern bool LoadD2D(); extern ID2D1Factory *pD2DFactory; extern IDWriteFactory *pIDWriteFactory; #endif } + +#endif diff --git a/scintilla/win32/ScintRes.rc b/scintilla/win32/ScintRes.rc index e62fc25d8..efcf590ad 100644 --- a/scintilla/win32/ScintRes.rc +++ b/scintilla/win32/ScintRes.rc @@ -6,8 +6,8 @@ #include -#define VERSION_SCINTILLA "5.0.0" -#define VERSION_WORDS 5, 0, 0, 0 +#define VERSION_SCINTILLA "5.0.1" +#define VERSION_WORDS 5, 0, 1, 0 VS_VERSION_INFO VERSIONINFO FILEVERSION VERSION_WORDS @@ -30,7 +30,7 @@ BEGIN VALUE "FileDescription", "Scintilla.DLL - a Source Editing Component vNP3\0" VALUE "FileVersion", VERSION_SCINTILLA "\0" VALUE "InternalName", "Scintilla vNP3\0" - VALUE "LegalCopyright", "Copyright 1998-2020 by Neil Hodgson\0" + VALUE "LegalCopyright", "Copyright 1998-2021 by Neil Hodgson\0" VALUE "OriginalFilename", "Scintilla.DLL\0" VALUE "ProductName", "Scintilla vNP3\0" VALUE "ProductVersion", VERSION_SCINTILLA "\0" diff --git a/scintilla/win32/ScintillaWin.cxx b/scintilla/win32/ScintillaWin.cxx index 04510a30e..e06e95d80 100644 --- a/scintilla/win32/ScintillaWin.cxx +++ b/scintilla/win32/ScintillaWin.cxx @@ -24,26 +24,16 @@ #include #include #include -//#include +#include // Want to use std::min and std::max so don't want Windows.h version of min and max #if !defined(NOMINMAX) #define NOMINMAX #endif - -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x601 /*_WIN32_WINNT_WIN7*/ -#endif -#ifndef WINVER -#define WINVER 0x601 /*_WIN32_WINNT_WIN7*/ -#endif -#ifndef NTDDI_VERSION -#define NTDDI_VERSION 0x06010000 /*NTDDI_WIN7*/ -#endif - -#define VC_EXTRALEAN 1 -#define WIN32_LEAN_AND_MEAN 1 - +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 +#undef WINVER +#define WINVER 0x0500 #include #include #include @@ -62,32 +52,13 @@ #include "Debugging.h" #include "Geometry.h" - -#include -#include -#include -#include - -#define DebugDragAndDropDataFormat 0 -#define MaxDragAndDropDataFormatCount 6 -/* -CF_VSSTGPROJECTITEMS, CF_VSREFPROJECTITEMS -https://docs.microsoft.com/en-us/visualstudio/extensibility/ux-guidelines/application-patterns-for-visual-studio -*/ -#define EnableDrop_VisualStudioProjectItem 1 -/* -Chromium Web Custom MIME Data Format -Used by VSCode, Atom etc. -*/ -#define Enable_ChromiumWebCustomMIMEDataFormat 0 - #include "Platform.h" #include "ILoader.h" #include "ILexer.h" #include "Scintilla.h" -//~#include "CharacterCategory.h" +#include "CharacterCategory.h" #include "Position.h" #include "UniqueString.h" #include "SplitVector.h" @@ -164,37 +135,40 @@ constexpr UINT SC_WIN_IDLE = 5001; constexpr UINT SC_WORK_IDLE = 5002; #define SC_INDICATOR_INPUT INDICATOR_IME -#define SC_INDICATOR_TARGET (INDICATOR_IME + 1) -#define SC_INDICATOR_CONVERTED (INDICATOR_IME + 2) +#define SC_INDICATOR_TARGET INDICATOR_IME+1 +#define SC_INDICATOR_CONVERTED INDICATOR_IME+2 #define SC_INDICATOR_UNKNOWN INDICATOR_IME_MAX -#if _WIN32_WINNT < _WIN32_WINNT_WIN8 -DWORD kSystemLibraryLoadFlags = 0; -using SetCoalescableTimerSig = UINT_PTR (WINAPI *)(HWND hwnd, UINT_PTR nIDEvent, - UINT uElapse, TIMERPROC lpTimerFunc, ULONG uToleranceDelay); +#ifndef SCS_CAP_SETRECONVERTSTRING +#define SCS_CAP_SETRECONVERTSTRING 0x00000004 +#define SCS_QUERYRECONVERTSTRING 0x00020000 +#define SCS_SETRECONVERTSTRING 0x00010000 #endif +typedef UINT_PTR (WINAPI *SetCoalescableTimerSig)(HWND hwnd, UINT_PTR nIDEvent, + UINT uElapse, TIMERPROC lpTimerFunc, ULONG uToleranceDelay); + +// GCC has trouble with the standard COM ABI so do it the old C way with explicit vtables. + using namespace Scintilla; namespace { -const TCHAR *callClassName = L"CallTip"; +const TCHAR callClassName[] = TEXT("CallTip"); -inline void SetWindowID(HWND hWnd, int identifier) noexcept { +void SetWindowID(HWND hWnd, int identifier) noexcept { ::SetWindowLongPtr(hWnd, GWLP_ID, identifier); } -constexpr Point PointFromLParam(sptr_t lpoint) noexcept { +Point PointFromLParam(sptr_t lpoint) noexcept { return Point::FromInts(GET_X_LPARAM(lpoint), GET_Y_LPARAM(lpoint)); } -inline bool KeyboardIsKeyDown(int key) noexcept { - // the return value is a SHORT (16 bits), not a 32 bit value - // (in other words, 0x80000000 is not a valid bit mask) - return (::GetKeyState(key) & 0x8000) != 0; +bool KeyboardIsKeyDown(int key) noexcept { + return (::GetKeyState(key) & 0x80000000) != 0; } -constexpr bool KeyboardIsNumericKeypadFunction(uptr_t wParam, sptr_t lParam) noexcept { +constexpr bool KeyboardIsNumericKeypadFunction(uptr_t wParam, sptr_t lParam) { // Bit 24 is the extended keyboard flag and the numeric keypad is non-extended if ((lParam & (1 << 24)) != 0) { // Not from the numeric keypad @@ -218,141 +192,60 @@ constexpr bool KeyboardIsNumericKeypadFunction(uptr_t wParam, sptr_t lParam) noe } } -inline CLIPFORMAT GetClipboardFormat(LPCWSTR name) noexcept { - return static_cast(::RegisterClipboardFormat(name)); -} - -#if 0 -inline void LazyGetClipboardFormat(UINT &fmt, LPCWSTR name) noexcept { - if (fmt == 0) { - fmt = ::RegisterClipboardFormat(name); - } -} -#endif - } class ScintillaWin; // Forward declaration for COM interface subobjects +typedef void VFunction(void); + + /** */ -class FormatEnumerator final : public IEnumFORMATETC { +class FormatEnumerator { +public: + VFunction **vtbl; ULONG ref; ULONG pos; std::vector formats; - -public: FormatEnumerator(ULONG pos_, const CLIPFORMAT formats_[], size_t formatsLen_); - virtual ~FormatEnumerator() = default; - - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, PVOID *ppv) noexcept override; - STDMETHODIMP_(ULONG)AddRef() noexcept override; - STDMETHODIMP_(ULONG)Release() noexcept override; - - // IEnumFORMATETC - STDMETHODIMP Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched) noexcept override; - STDMETHODIMP Skip(ULONG celt) noexcept override; - STDMETHODIMP Reset() noexcept override; - STDMETHODIMP Clone(IEnumFORMATETC **ppenum) override; }; /** */ -class DropSource final : public IDropSource { +class DropSource { public: - ScintillaWin *sci = nullptr; - DropSource() noexcept = default; - virtual ~DropSource() = default; - - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, PVOID *ppv) noexcept override; - STDMETHODIMP_(ULONG)AddRef() noexcept override; - STDMETHODIMP_(ULONG)Release() noexcept override; - - // IDropSource - STDMETHODIMP QueryContinueDrag(BOOL fEsc, DWORD grfKeyState) noexcept override; - STDMETHODIMP GiveFeedback(DWORD) noexcept override; + VFunction **vtbl; + ScintillaWin *sci; + DropSource() noexcept; }; /** */ -class DataObject final : public IDataObject { +class DataObject { public: - ScintillaWin *sci = nullptr; - DataObject() noexcept = default; - virtual ~DataObject() = default; - - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, PVOID *ppv) noexcept override; - STDMETHODIMP_(ULONG)AddRef() noexcept override; - STDMETHODIMP_(ULONG)Release() noexcept override; - - // IDataObject - STDMETHODIMP GetData(FORMATETC *pFEIn, STGMEDIUM *pSTM) override; - STDMETHODIMP GetDataHere(FORMATETC *, STGMEDIUM *) noexcept override; - STDMETHODIMP QueryGetData(FORMATETC *pFE) noexcept override; - STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *, FORMATETC *pFEOut) noexcept override; - STDMETHODIMP SetData(FORMATETC *, STGMEDIUM *, BOOL) noexcept override; - STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnum) override; - STDMETHODIMP DAdvise(FORMATETC *, DWORD, IAdviseSink *, PDWORD) noexcept override; - STDMETHODIMP DUnadvise(DWORD) noexcept override; - STDMETHODIMP EnumDAdvise(IEnumSTATDATA **) noexcept override; + VFunction **vtbl; + ScintillaWin *sci; + DataObject() noexcept; }; /** */ -class DropTarget final : public IDropTarget { +class DropTarget { public: - ScintillaWin *sci = nullptr; - DropTarget() noexcept = default; - virtual ~DropTarget() = default; - - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, PVOID *ppv) noexcept override; - STDMETHODIMP_(ULONG)AddRef() noexcept override; - STDMETHODIMP_(ULONG)Release() noexcept override; - - // IDropTarget - STDMETHODIMP DragEnter(LPDATAOBJECT pIDataSource, DWORD grfKeyState, POINTL pt, PDWORD pdwEffect) override; - STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, PDWORD pdwEffect) override; - STDMETHODIMP DragLeave() override; - STDMETHODIMP Drop(LPDATAOBJECT pIDataSource, DWORD grfKeyState, POINTL pt, PDWORD pdwEffect) override; + VFunction **vtbl; + ScintillaWin *sci; + DropTarget() noexcept; }; namespace { -// InputLanguage() and SetCandidateWindowPos() are based on Chromium's IMM32Manager and InputMethodWinImm32. -// https://github.com/chromium/chromium/blob/master/ui/base/ime/win/imm32_manager.cc -// See License.txt or https://github.com/chromium/chromium/blob/master/LICENSE for license details. - -// See Chromium's IMM32Manager::SetInputLanguage() -LANGID InputLanguage() noexcept { - // Retrieve the current input language from the system's keyboard layout. - // Using GetKeyboardLayoutName instead of GetKeyboardLayout, because - // the language from GetKeyboardLayout is the language under where the - // keyboard layout is installed. And the language from GetKeyboardLayoutName - // indicates the language of the keyboard layout itself. - // See crbug.com/344834. - LANGID inputLang; - WCHAR keyboard_layout[KL_NAMELENGTH]; - if (::GetKeyboardLayoutNameW(keyboard_layout)) { - inputLang = static_cast(wcstol(&keyboard_layout[KL_NAMELENGTH >> 1], nullptr, 16)); - } else { - /// TODO: Fallback to en-US? - HKL inputLocale = ::GetKeyboardLayout(0); - inputLang = LOWORD(inputLocale); - } - //Platform::DebugPrintf("InputLanguage(): %04X\n", inputLang); - return inputLang; -} - class IMContext { HWND hwnd; public: HIMC hIMC; - explicit IMContext(HWND hwnd_) noexcept : - hwnd(hwnd_), hIMC(::ImmGetContext(hwnd_)) {} + IMContext(HWND hwnd_) noexcept : + hwnd(hwnd_), hIMC(::ImmGetContext(hwnd_)) { + } // Deleted so IMContext objects can not be copied. IMContext(const IMContext &) = delete; IMContext(IMContext &&) = delete; @@ -363,29 +256,21 @@ public: ::ImmReleaseContext(hwnd, hIMC); } - operator bool() const noexcept { - return hIMC != nullptr; - } - - LONG GetImeCaretPos() const noexcept { + unsigned int GetImeCaretPos() const noexcept { return ImmGetCompositionStringW(hIMC, GCS_CURSORPOS, nullptr, 0); } - std::vector GetImeAttributes() const { - const LONG attrLen = ::ImmGetCompositionStringW(hIMC, GCS_COMPATTR, nullptr, 0); + std::vector GetImeAttributes() { + const int attrLen = ::ImmGetCompositionStringW(hIMC, GCS_COMPATTR, nullptr, 0); std::vector attr(attrLen, 0); - ::ImmGetCompositionStringW(hIMC, GCS_COMPATTR, attr.data(), static_cast(attr.size())); + ::ImmGetCompositionStringW(hIMC, GCS_COMPATTR, &attr[0], static_cast(attr.size())); return attr; } - LONG HasCompositionString(DWORD dwIndex) const noexcept { - return hIMC ? ::ImmGetCompositionStringW(hIMC, dwIndex, nullptr, 0) : 0; - } - - std::wstring GetCompositionString(DWORD dwIndex) const { + std::wstring GetCompositionString(DWORD dwIndex) { const LONG byteLen = ::ImmGetCompositionStringW(hIMC, dwIndex, nullptr, 0); - std::wstring wcs(byteLen / sizeof(wchar_t), 0); - ::ImmGetCompositionStringW(hIMC, dwIndex, wcs.data(), byteLen); + std::wstring wcs(byteLen / 2, 0); + ::ImmGetCompositionStringW(hIMC, dwIndex, &wcs[0], byteLen); return wcs; } }; @@ -393,11 +278,11 @@ public: class GlobalMemory; class ReverseArrowCursor { - DPI_T dpi = { USER_DEFAULT_SCREEN_DPI, USER_DEFAULT_SCREEN_DPI }; + UINT dpi = USER_DEFAULT_SCREEN_DPI; HCURSOR cursor {}; public: - ReverseArrowCursor() noexcept = default; + ReverseArrowCursor() noexcept {} // Deleted so ReverseArrowCursor objects can not be copied. ReverseArrowCursor(const ReverseArrowCursor &) = delete; ReverseArrowCursor(ReverseArrowCursor &&) = delete; @@ -409,9 +294,9 @@ public: } } - HCURSOR Load(DPI_T dpi_) noexcept { + HCURSOR Load(UINT dpi_) noexcept { if (cursor) { - if ((dpi.x == dpi_.x) && (dpi.y == dpi_.y)) { + if (dpi == dpi_) { return cursor; } ::DestroyCursor(cursor); @@ -427,7 +312,7 @@ public: /** */ -class ScintillaWin final : +class ScintillaWin : public ScintillaBase { bool lastKeyDownConsumed; @@ -435,16 +320,12 @@ class ScintillaWin final : bool capturedMouse; bool trackedMouseLeave; -#if _WIN32_WINNT < _WIN32_WINNT_WIN8 SetCoalescableTimerSig SetCoalescableTimerFn; -#endif - UINT linesPerScroll; ///< Intellimouse support - UINT charsPerScroll; ///< Intellimouse support - int wheelDelta; ///< Wheel delta from roll - int wheelDeltaH; ///< Wheel delta from horizontal wheel roll + unsigned int linesPerScroll; ///< Intellimouse support + int wheelDelta; ///< Wheel delta from roll - DPI_T dpi = { USER_DEFAULT_SCREEN_DPI, USER_DEFAULT_SCREEN_DPI }; + UINT dpi = USER_DEFAULT_SCREEN_DPI; ReverseArrowCursor reverseArrowCursor; HRGN hRgnUpdate; @@ -452,23 +333,11 @@ class ScintillaWin final : bool hasOKText; CLIPFORMAT cfColumnSelect; - UINT cfBorlandIDEBlockType; - UINT cfLineSelect; - UINT cfVSLineTag; + CLIPFORMAT cfBorlandIDEBlockType; + CLIPFORMAT cfLineSelect; + CLIPFORMAT cfVSLineTag; -#if EnableDrop_VisualStudioProjectItem - CLIPFORMAT cfVSStgProjectItem; - CLIPFORMAT cfVSRefProjectItem; -#endif -#if Enable_ChromiumWebCustomMIMEDataFormat - CLIPFORMAT cfChromiumCustomMIME; -#endif - - // supported drag & drop format - CLIPFORMAT dropFormat[MaxDragAndDropDataFormatCount]; - UINT dropFormatCount; - - //HRESULT hrOle; + HRESULT hrOle; DropSource ds; DataObject dob; DropTarget dt; @@ -477,44 +346,37 @@ class ScintillaWin final : static ATOM scintillaClassAtom; static ATOM callClassAtom; - // The current input Language ID. - LANGID inputLang; - #if defined(USE_D2D) ID2D1RenderTarget *pRenderTarget; bool renderTargetValid; #endif - explicit ScintillaWin(HWND hwnd) noexcept; - // virtual ~ScintillaWin() in public section + explicit ScintillaWin(HWND hwnd); + // Deleted so ScintillaWin objects can not be copied. + ScintillaWin(const ScintillaWin &) = delete; + ScintillaWin(ScintillaWin &&) = delete; + ScintillaWin &operator=(const ScintillaWin &) = delete; + ScintillaWin &operator=(ScintillaWin &&) = delete; + // ~ScintillaWin() in public section - void Init() noexcept; - void Finalise() noexcept override; + void Init(); + void Finalise() override; #if defined(USE_D2D) - void EnsureRenderTarget(HDC hdc) noexcept; - void DropRenderTarget() noexcept; + void EnsureRenderTarget(HDC hdc); + void DropRenderTarget(); #endif HWND MainHWND() const noexcept; -#if DebugDragAndDropDataFormat - void EnumDataSourceFormat(const char *tag, LPDATAOBJECT pIDataSource); - void EnumAllClipboardFormat(const char *tag); -#else - #define EnumDataSourceFormat(tag, pIDataSource) - #define EnumAllClipboardFormat(tag) -#endif static sptr_t DirectFunction( - sptr_t ptr, UINT iMessage, uptr_t wParam, sptr_t lParam); - static LRESULT CALLBACK SWndProc( - HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam); - static LRESULT CALLBACK CTWndProc( - HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam); + sptr_t ptr, UINT iMessage, uptr_t wParam, sptr_t lParam); + static LRESULT PASCAL SWndProc( + HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam); + static LRESULT PASCAL CTWndProc( + HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam); - enum : UINT_PTR { - invalidTimerID, standardTimerID, idleTimerID, fineTimerStart - }; + enum : UINT_PTR { invalidTimerID, standardTimerID, idleTimerID, fineTimerStart }; - void DisplayCursor(Window::Cursor c) noexcept override; + void DisplayCursor(Window::Cursor c) override; bool DragThreshold(Point ptStart, Point ptNow) noexcept override; void StartDrag() override; static int MouseModifiers(uptr_t wParam) noexcept; @@ -525,14 +387,14 @@ class ScintillaWin final : bool PaintDC(HDC hdc); sptr_t WndPaint(); + // DBCS + void ImeStartComposition(); + void ImeEndComposition(); + LRESULT ImeOnReconvert(LPARAM lParam); sptr_t HandleCompositionWindowed(uptr_t wParam, sptr_t lParam); sptr_t HandleCompositionInline(uptr_t wParam, sptr_t lParam); static bool KoreanIME() noexcept; -// >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> - bool IsIMEOpen(); - DWORD GetIMEInputMode(); -// <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< - void MoveImeCarets(Sci::Position offset) noexcept; + void MoveImeCarets(Sci::Position offset); void DrawImeIndicator(int indicator, Sci::Position len); void SetCandidateWindowPos(); void SelectionToHangul(); @@ -541,76 +403,69 @@ class ScintillaWin final : void AddWString(std::wstring_view wsv, CharacterSource charSource); UINT CodePageOfDocument() const noexcept; - bool ValidCodePage(int codePage) const noexcept override; + bool ValidCodePage(int codePage) const override; std::string UTF8FromEncoded(std::string_view encoded) const override; std::string EncodedFromUTF8(std::string_view utf8) const override; std::string EncodeWString(std::wstring_view wsv); - sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) noexcept override; + sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) override; void IdleWork() override; - void QueueIdleWork(WorkItems items, Sci::Position upTo) noexcept override; - bool SetIdle(bool on) noexcept override; + void QueueIdleWork(WorkItems items, Sci::Position upTo) override; + bool SetIdle(bool on) override; UINT_PTR timers[static_cast(TickReason::dwell)+1] {}; - bool FineTickerRunning(TickReason reason) noexcept override; - void FineTickerStart(TickReason reason, int millis, int tolerance) noexcept override; - void FineTickerCancel(TickReason reason) noexcept override; - void SetMouseCapture(bool on) noexcept override; - bool HaveMouseCapture() noexcept override; + bool FineTickerRunning(TickReason reason) override; + void FineTickerStart(TickReason reason, int millis, int tolerance) override; + void FineTickerCancel(TickReason reason) override; + void SetMouseCapture(bool on) override; + bool HaveMouseCapture() override; void SetTrackMouseLeaveEvent(bool on) noexcept; bool PaintContains(PRectangle rc) const noexcept override; void ScrollText(Sci::Line linesToMove) override; - void NotifyCaretMove() noexcept override; + void NotifyCaretMove() override; void UpdateSystemCaret() override; void SetVerticalScrollPos() override; void SetHorizontalScrollPos() override; bool ModifyScrollBars(Sci::Line nMax, Sci::Line nPage) override; - void NotifyChange() noexcept override; + void NotifyChange() override; void NotifyFocus(bool focus) override; - void SetCtrlID(int identifier) noexcept override; + void SetCtrlID(int identifier) override; int GetCtrlID() const noexcept override; - void NotifyParent(SCNotification scn) noexcept override; + void NotifyParent(SCNotification scn) override; void NotifyDoubleClick(Point pt, int modifiers) override; - void NotifyURIDropped(const char *list) noexcept; std::unique_ptr CaseFolderForEncoding() override; std::string CaseMapString(const std::string &s, CaseMapping caseMapping) override; - void Copy(bool asBinary) override; - bool CanPaste() noexcept override; - void Paste(bool asBinary) override; - void CreateCallTipWindow(PRectangle rc) noexcept override; -#if SCI_EnablePopupMenu - void AddToPopUp(const char *label, int cmd = 0, bool enabled = true) noexcept override; -#endif - void ClaimSelection() noexcept override; - - // DBCS - void ImeStartComposition(); - void ImeEndComposition(); - LRESULT ImeOnReconvert(LPARAM lParam); - - enum class CopyEncoding { - Unicode, // used in Copy & Paste, Drag & Drop - Ansi, // used in Drag & Drop for CF_TEXT - Binary, // used in Copy & Paste for asBinary - }; + void Copy() override; + bool CanPaste() override; + void Paste() override; + void CreateCallTipWindow(PRectangle rc) override; + // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> + #if SCI_EnablePopupMenu + void AddToPopUp(const char* label, int cmd = 0, bool enabled = true) override; + #endif + // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< + void ClaimSelection() override; void GetIntelliMouseParameters() noexcept; - void CopyToGlobal(GlobalMemory &gmUnicode, const SelectionText &selectedText, CopyEncoding encoding); + void CopyToGlobal(GlobalMemory &gmUnicode, const SelectionText &selectedText); void CopyToClipboard(const SelectionText &selectedText) override; void ScrollMessage(WPARAM wParam); void HorizontalScrollMessage(WPARAM wParam); void FullPaint(); void FullPaintDC(HDC hdc); - bool IsCompatibleDC(HDC hOtherDC) const noexcept; + bool IsCompatibleDC(HDC hOtherDC) noexcept; DWORD EffectFromState(DWORD grfKeyState) const noexcept; - int SetScrollInfo(int nBar, LPCSCROLLINFO lpsi, BOOL bRedraw) const noexcept; - bool GetScrollInfo(int nBar, LPSCROLLINFO lpsi) const noexcept; + int SetScrollInfo(int nBar, LPCSCROLLINFO lpsi, BOOL bRedraw) noexcept; + bool GetScrollInfo(int nBar, LPSCROLLINFO lpsi) noexcept; void ChangeScrollPos(int barType, Sci::Position pos); - sptr_t GetTextLength() const noexcept; - sptr_t GetText(uptr_t wParam, sptr_t lParam) const; - Window::Cursor SCICALL ContextCursor(Point pt); + sptr_t GetTextLength(); + sptr_t GetText(uptr_t wParam, sptr_t lParam); + Window::Cursor ContextCursor(Point pt); + // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> + #if SCI_EnablePopupMenu sptr_t ShowContextMenu(unsigned int iMessage, uptr_t wParam, sptr_t lParam); - + #endif + // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< void SizeWindow(); sptr_t MouseMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam); sptr_t KeyMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam); @@ -623,38 +478,33 @@ class ScintillaWin final : public: ~ScintillaWin() override; - // Deleted so ScintillaWin objects can not be copied. - ScintillaWin(const ScintillaWin &) = delete; - ScintillaWin(ScintillaWin &&) = delete; - ScintillaWin &operator=(const ScintillaWin &) = delete; - ScintillaWin &operator=(ScintillaWin &&) = delete; // Public for benefit of Scintilla_DirectFunction sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) override; /// Implement IUnknown - STDMETHODIMP QueryInterface(REFIID riid, PVOID *ppv) noexcept; - STDMETHODIMP_(ULONG)AddRef() noexcept; - STDMETHODIMP_(ULONG)Release() noexcept; + STDMETHODIMP QueryInterface(REFIID riid, PVOID *ppv); + STDMETHODIMP_(ULONG)AddRef(); + STDMETHODIMP_(ULONG)Release(); /// Implement IDropTarget STDMETHODIMP DragEnter(LPDATAOBJECT pIDataSource, DWORD grfKeyState, - POINTL pt, PDWORD pdwEffect); + POINTL pt, PDWORD pdwEffect); STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, PDWORD pdwEffect); STDMETHODIMP DragLeave(); STDMETHODIMP Drop(LPDATAOBJECT pIDataSource, DWORD grfKeyState, - POINTL pt, PDWORD pdwEffect); + POINTL pt, PDWORD pdwEffect); /// Implement important part of IDataObject - STDMETHODIMP GetData(const FORMATETC *pFEIn, STGMEDIUM *pSTM); + STDMETHODIMP GetData(FORMATETC *pFEIn, STGMEDIUM *pSTM); - static BOOL CALLBACK PrepareOnce(PINIT_ONCE initOnce, PVOID parameter, PVOID *lpContext) noexcept; + static void Prepare() noexcept; static bool Register(HINSTANCE hInstance_) noexcept; static bool Unregister() noexcept; friend class DropSource; friend class DataObject; friend class DropTarget; - bool DragIsRectangularOK(UINT fmt) const noexcept { + bool DragIsRectangularOK(CLIPFORMAT fmt) const noexcept { return drag.rectangular && (fmt == cfColumnSelect); } @@ -673,23 +523,19 @@ HINSTANCE ScintillaWin::hInstance {}; ATOM ScintillaWin::scintillaClassAtom = 0; ATOM ScintillaWin::callClassAtom = 0; -ScintillaWin::ScintillaWin(HWND hwnd) noexcept { +ScintillaWin::ScintillaWin(HWND hwnd) { lastKeyDownConsumed = false; lastHighSurrogateChar = 0; capturedMouse = false; trackedMouseLeave = false; -#if _WIN32_WINNT < _WIN32_WINNT_WIN8 SetCoalescableTimerFn = nullptr; -#endif linesPerScroll = 0; - charsPerScroll = 0; - wheelDelta = 0; // Wheel delta from roll - wheelDeltaH = 0; // H-Wheel delta from roll + wheelDelta = 0; // Wheel delta from roll - dpi = GetWindowDPI(hwnd); + dpi = DpiForWindow(hwnd); hRgnUpdate = {}; @@ -697,36 +543,18 @@ ScintillaWin::ScintillaWin(HWND hwnd) noexcept { // There does not seem to be a real standard for indicating that the clipboard // contains a rectangular selection, so copy Developer Studio and Borland Delphi. - cfColumnSelect = GetClipboardFormat(L"MSDEVColumnSelect"); - cfBorlandIDEBlockType = ::RegisterClipboardFormat(L"Borland IDE Block Type"); + cfColumnSelect = static_cast( + ::RegisterClipboardFormat(TEXT("MSDEVColumnSelect"))); + cfBorlandIDEBlockType = static_cast( + ::RegisterClipboardFormat(TEXT("Borland IDE Block Type"))); // Likewise for line-copy (copies a full line when no text is selected) - cfLineSelect = ::RegisterClipboardFormat(L"MSDEVLineSelect"); - cfVSLineTag = ::RegisterClipboardFormat(L"VisualStudioEditorOperationsLineCutCopyClipboardTag"); + cfLineSelect = static_cast( + ::RegisterClipboardFormat(TEXT("MSDEVLineSelect"))); + cfVSLineTag = static_cast( + ::RegisterClipboardFormat(TEXT("VisualStudioEditorOperationsLineCutCopyClipboardTag"))); + hrOle = E_FAIL; -#if EnableDrop_VisualStudioProjectItem - cfVSStgProjectItem = GetClipboardFormat(L"CF_VSSTGPROJECTITEMS"); - cfVSRefProjectItem = GetClipboardFormat(L"CF_VSREFPROJECTITEMS"); -#endif -#if Enable_ChromiumWebCustomMIMEDataFormat - cfChromiumCustomMIME = GetClipboardFormat(L"Chromium Web Custom MIME Data Format"); -#endif - - UINT index = 0; - dropFormat[index++] = CF_HDROP; -#if EnableDrop_VisualStudioProjectItem - dropFormat[index++] = cfVSStgProjectItem; - dropFormat[index++] = cfVSRefProjectItem; -#endif -#if Enable_ChromiumWebCustomMIMEDataFormat - dropFormat[index++] = cfChromiumCustomMIME; -#endif - // text format comes last - dropFormat[index++] = CF_UNICODETEXT; - dropFormat[index++] = CF_TEXT; - dropFormatCount = index; - - //hrOle = E_FAIL; wMain = hwnd; dob.sci = this; @@ -736,7 +564,6 @@ ScintillaWin::ScintillaWin(HWND hwnd) noexcept { sysCaretBitmap = {}; sysCaretWidth = 0; sysCaretHeight = 0; - inputLang = LANG_USER_DEFAULT; styleIdleInQueue = false; @@ -752,19 +579,17 @@ ScintillaWin::ScintillaWin(HWND hwnd) noexcept { Init(); } -ScintillaWin::~ScintillaWin() { Finalise(); } +ScintillaWin::~ScintillaWin() {} -void ScintillaWin::Init() noexcept { +void ScintillaWin::Init() { // Initialize COM. If the app has already done this it will have // no effect. If the app hasn't, we really shouldn't ask them to call // it just so this internal feature works. - //hrOle = ::OleInitialize(nullptr); + hrOle = ::OleInitialize(nullptr); // Find SetCoalescableTimer which is only available from Windows 8+ -#if _WIN32_WINNT < _WIN32_WINNT_WIN8 HMODULE user32 = ::GetModuleHandleW(L"user32.dll"); SetCoalescableTimerFn = DLLFunction(user32, "SetCoalescableTimer"); -#endif vs.indicators[SC_INDICATOR_UNKNOWN] = Indicator(INDIC_HIDDEN, ColourDesired(0, 0, 0xff)); vs.indicators[SC_INDICATOR_INPUT] = Indicator(INDIC_DOTS, ColourDesired(0, 0, 0xff)); @@ -772,7 +597,7 @@ void ScintillaWin::Init() noexcept { vs.indicators[SC_INDICATOR_TARGET] = Indicator(INDIC_STRAIGHTBOX, ColourDesired(0, 0, 0xff)); } -void ScintillaWin::Finalise() noexcept { +void ScintillaWin::Finalise() { ScintillaBase::Finalise(); for (TickReason tr = TickReason::caret; tr <= TickReason::dwell; tr = static_cast(static_cast(tr) + 1)) { @@ -783,14 +608,14 @@ void ScintillaWin::Finalise() noexcept { DropRenderTarget(); #endif ::RevokeDragDrop(MainHWND()); - //if (SUCCEEDED(hrOle)) { - // ::OleUninitialize(); - //} + if (SUCCEEDED(hrOle)) { + ::OleUninitialize(); + } } #if defined(USE_D2D) -void ScintillaWin::EnsureRenderTarget(HDC hdc) noexcept { +void ScintillaWin::EnsureRenderTarget(HDC hdc) { if (!renderTargetValid) { DropRenderTarget(); renderTargetValid = true; @@ -805,7 +630,6 @@ void ScintillaWin::EnsureRenderTarget(HDC hdc) noexcept { // Create a Direct2D render target. #if 1 D2D1_RENDER_TARGET_PROPERTIES drtp; - ZeroMemory(&drtp, sizeof(D2D1_RENDER_TARGET_PROPERTIES)); drtp.type = D2D1_RENDER_TARGET_TYPE_DEFAULT; drtp.pixelFormat.format = DXGI_FORMAT_UNKNOWN; drtp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_UNKNOWN; @@ -824,33 +648,30 @@ void ScintillaWin::EnsureRenderTarget(HDC hdc) noexcept { if (SUCCEEDED(hr)) { pRenderTarget = pDCRT; } else { - //Platform::DebugPrintf("Failed CreateDCRenderTarget 0x%lx\n", hr); - ReleaseUnknown(pDCRT); + Platform::DebugPrintf("Failed CreateDCRenderTarget 0x%lx\n", hr); pRenderTarget = nullptr; } } else { D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp; - ZeroMemory(&dhrtp, sizeof(D2D1_HWND_RENDER_TARGET_PROPERTIES)); dhrtp.hwnd = hw; dhrtp.pixelSize = size; dhrtp.presentOptions = (technology == SC_TECHNOLOGY_DIRECTWRITERETAIN) ? - D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS : D2D1_PRESENT_OPTIONS_NONE; + D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS : D2D1_PRESENT_OPTIONS_NONE; ID2D1HwndRenderTarget *pHwndRenderTarget = nullptr; const HRESULT hr = pD2DFactory->CreateHwndRenderTarget(drtp, dhrtp, &pHwndRenderTarget); if (SUCCEEDED(hr)) { pRenderTarget = pHwndRenderTarget; } else { - //Platform::DebugPrintf("Failed CreateHwndRenderTarget 0x%lx\n", hr); - ReleaseUnknown(pHwndRenderTarget); + Platform::DebugPrintf("Failed CreateHwndRenderTarget 0x%lx\n", hr); pRenderTarget = nullptr; } } #else pD2DFactory->CreateHwndRenderTarget( D2D1::RenderTargetProperties( - D2D1_RENDER_TARGET_TYPE_DEFAULT, + D2D1_RENDER_TARGET_TYPE_DEFAULT , D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), 96.0f, 96.0f, D2D1_RENDER_TARGET_USAGE_NONE, D2D1_FEATURE_LEVEL_DEFAULT), D2D1::HwndRenderTargetProperties(hw, size), @@ -866,13 +687,13 @@ void ScintillaWin::EnsureRenderTarget(HDC hdc) noexcept { GetClientRect(MainHWND(), &rcWindow); const HRESULT hr = static_cast(pRenderTarget)->BindDC(hdc, &rcWindow); if (FAILED(hr)) { - //Platform::DebugPrintf("BindDC failed 0x%lx\n", hr); + Platform::DebugPrintf("BindDC failed 0x%lx\n", hr); DropRenderTarget(); } } } -void ScintillaWin::DropRenderTarget() noexcept { +void ScintillaWin::DropRenderTarget() { ReleaseUnknown(pRenderTarget); } @@ -882,7 +703,7 @@ HWND ScintillaWin::MainHWND() const noexcept { return HwndFromWindow(wMain); } -void ScintillaWin::DisplayCursor(Window::Cursor c) noexcept { +void ScintillaWin::DisplayCursor(Window::Cursor c) { if (cursorMode != SC_CURSORNORMAL) { c = static_cast(cursorMode); } @@ -897,8 +718,8 @@ bool ScintillaWin::DragThreshold(Point ptStart, Point ptNow) noexcept { const Point ptDifference = ptStart - ptNow; const XYPOSITION xMove = std::trunc(std::abs(ptDifference.x)); const XYPOSITION yMove = std::trunc(std::abs(ptDifference.y)); - return (xMove > SystemMetricsForDpi(SM_CXDRAG, dpi.x)) || - (yMove > SystemMetricsForDpi(SM_CYDRAG, dpi.y)); + return (xMove > SystemMetricsForDpi(SM_CXDRAG, dpi)) || + (yMove > SystemMetricsForDpi(SM_CYDRAG, dpi)); } void ScintillaWin::StartDrag() { @@ -907,12 +728,12 @@ void ScintillaWin::StartDrag() { dropWentOutside = true; IDataObject *pDataObject = reinterpret_cast(&dob); IDropSource *pDropSource = reinterpret_cast(&ds); - //Platform::DebugPrintf("About to DoDragDrop %p %p\n", pDataObject, pDropSource); + //Platform::DebugPrintf("About to DoDragDrop %x %x\n", pDataObject, pDropSource); const HRESULT hr = ::DoDragDrop( - pDataObject, - pDropSource, - DROPEFFECT_COPY | DROPEFFECT_MOVE, &dwEffect); - //Platform::DebugPrintf("DoDragDrop = %lx\n", hr); + pDataObject, + pDropSource, + DROPEFFECT_COPY | DROPEFFECT_MOVE, &dwEffect); + //Platform::DebugPrintf("DoDragDrop = %x\n", hr); if (SUCCEEDED(hr)) { if ((hr == DRAGDROP_S_DROP) && (dwEffect == DROPEFFECT_MOVE) && dropWentOutside) { // Remove dragged out text @@ -932,46 +753,46 @@ int ScintillaWin::MouseModifiers(uptr_t wParam) noexcept { namespace { int InputCodePage() noexcept { - HKL const inputLocale = ::GetKeyboardLayout(0); + HKL inputLocale = ::GetKeyboardLayout(0); const LANGID inputLang = LOWORD(inputLocale); - WCHAR sCodePage[32]; - const int res = ::GetLocaleInfo(MAKELCID(inputLang, SORT_DEFAULT), - LOCALE_IDEFAULTANSICODEPAGE, sCodePage, sizeof(sCodePage) / sizeof(WCHAR)); + char sCodePage[10]; + const int res = ::GetLocaleInfoA(MAKELCID(inputLang, SORT_DEFAULT), + LOCALE_IDEFAULTANSICODEPAGE, sCodePage, sizeof(sCodePage)); if (!res) return 0; - return static_cast(wcstol(sCodePage, nullptr, 32)); + return atoi(sCodePage); } /** Map the key codes to their equivalent SCK_ form. */ int KeyTranslate(int keyIn) noexcept { - //PLATFORM_ASSERT(!keyIn); +//PLATFORM_ASSERT(!keyIn); switch (keyIn) { - case VK_DOWN: return SCK_DOWN; - case VK_UP: return SCK_UP; - case VK_LEFT: return SCK_LEFT; - case VK_RIGHT: return SCK_RIGHT; - case VK_HOME: return SCK_HOME; - case VK_END: return SCK_END; - case VK_PRIOR: return SCK_PRIOR; - case VK_NEXT: return SCK_NEXT; - case VK_DELETE: return SCK_DELETE; - case VK_INSERT: return SCK_INSERT; - case VK_ESCAPE: return SCK_ESCAPE; - case VK_BACK: return SCK_BACK; - case VK_TAB: return SCK_TAB; - case VK_RETURN: return SCK_RETURN; - case VK_ADD: return SCK_ADD; - case VK_SUBTRACT: return SCK_SUBTRACT; - case VK_DIVIDE: return SCK_DIVIDE; - case VK_LWIN: return SCK_WIN; - case VK_RWIN: return SCK_RWIN; - case VK_APPS: return SCK_MENU; - case VK_OEM_2: return '/'; - case VK_OEM_3: return '`'; - case VK_OEM_4: return '['; - case VK_OEM_5: return '\\'; - case VK_OEM_6: return ']'; - default: return keyIn; + case VK_DOWN: return SCK_DOWN; + case VK_UP: return SCK_UP; + case VK_LEFT: return SCK_LEFT; + case VK_RIGHT: return SCK_RIGHT; + case VK_HOME: return SCK_HOME; + case VK_END: return SCK_END; + case VK_PRIOR: return SCK_PRIOR; + case VK_NEXT: return SCK_NEXT; + case VK_DELETE: return SCK_DELETE; + case VK_INSERT: return SCK_INSERT; + case VK_ESCAPE: return SCK_ESCAPE; + case VK_BACK: return SCK_BACK; + case VK_TAB: return SCK_TAB; + case VK_RETURN: return SCK_RETURN; + case VK_ADD: return SCK_ADD; + case VK_SUBTRACT: return SCK_SUBTRACT; + case VK_DIVIDE: return SCK_DIVIDE; + case VK_LWIN: return SCK_WIN; + case VK_RWIN: return SCK_RWIN; + case VK_APPS: return SCK_MENU; + case VK_OEM_2: return '/'; + case VK_OEM_3: return '`'; + case VK_OEM_4: return '['; + case VK_OEM_5: return '\\'; + case VK_OEM_6: return ']'; + default: return keyIn; } } @@ -1002,23 +823,23 @@ bool BoundsContains(PRectangle rcBounds, HRGN hRgnBounds, PRectangle rcCheck) no // Simplify calling WideCharToMultiByte and MultiByteToWideChar by providing default parameters and using string view. -inline int MultiByteFromWideChar(UINT codePage, std::wstring_view wsv, LPSTR lpMultiByteStr, ptrdiff_t cbMultiByte) noexcept { +int MultiByteFromWideChar(UINT codePage, std::wstring_view wsv, LPSTR lpMultiByteStr, ptrdiff_t cbMultiByte) noexcept { return ::WideCharToMultiByte(codePage, 0, wsv.data(), static_cast(wsv.length()), lpMultiByteStr, static_cast(cbMultiByte), nullptr, nullptr); } -inline int MultiByteLenFromWideChar(UINT codePage, std::wstring_view wsv) noexcept { +int MultiByteLenFromWideChar(UINT codePage, std::wstring_view wsv) noexcept { return MultiByteFromWideChar(codePage, wsv, nullptr, 0); } -inline int WideCharFromMultiByte(UINT codePage, std::string_view sv, LPWSTR lpWideCharStr, ptrdiff_t cchWideChar) noexcept { +int WideCharFromMultiByte(UINT codePage, std::string_view sv, LPWSTR lpWideCharStr, ptrdiff_t cchWideChar) noexcept { return ::MultiByteToWideChar(codePage, 0, sv.data(), static_cast(sv.length()), lpWideCharStr, static_cast(cchWideChar)); } -inline int WideCharLenFromMultiByte(UINT codePage, std::string_view sv) noexcept { +int WideCharLenFromMultiByte(UINT codePage, std::string_view sv) noexcept { return WideCharFromMultiByte(codePage, sv, nullptr, 0); } -std::string StringEncode(const std::wstring_view wsv, int codePage) { +std::string StringEncode(std::wstring_view wsv, int codePage) { const int cchMulti = wsv.length() ? MultiByteLenFromWideChar(codePage, wsv) : 0; std::string sMulti(cchMulti, 0); if (cchMulti) { @@ -1027,7 +848,7 @@ std::string StringEncode(const std::wstring_view wsv, int codePage) { return sMulti; } -std::wstring StringDecode(const std::string_view sv, int codePage) { +std::wstring StringDecode(std::string_view sv, int codePage) { const int cchWide = sv.length() ? WideCharLenFromMultiByte(codePage, sv) : 0; std::wstring sWide(cchWide, 0); if (cchWide) { @@ -1036,12 +857,12 @@ std::wstring StringDecode(const std::string_view sv, int codePage) { return sWide; } -std::wstring StringMapCase(const std::wstring_view wsv, DWORD mapFlags) { - const int charsConverted = ::LCMapStringW(LOCALE_USER_DEFAULT, mapFlags, +std::wstring StringMapCase(std::wstring_view wsv, DWORD mapFlags) { + const int charsConverted = ::LCMapStringW(LOCALE_SYSTEM_DEFAULT, mapFlags, wsv.data(), static_cast(wsv.length()), nullptr, 0); std::wstring wsConverted(charsConverted, 0); if (charsConverted) { - ::LCMapStringW(LOCALE_USER_DEFAULT, mapFlags, + ::LCMapStringW(LOCALE_SYSTEM_DEFAULT, mapFlags, wsv.data(), static_cast(wsv.length()), wsConverted.data(), charsConverted); } return wsConverted; @@ -1085,12 +906,11 @@ Sci::Position ScintillaWin::EncodedFromUTF8(const char *utf8, char *encoded) con const std::string_view utf8Input(utf8, inputLength); const int charsLen = WideCharLenFromMultiByte(CP_UTF8, utf8Input); std::wstring characters(charsLen, L'\0'); - WideCharFromMultiByte(CP_UTF8, utf8Input, characters.data(), charsLen); + WideCharFromMultiByte(CP_UTF8, utf8Input, &characters[0], charsLen); - const UINT codePage = CodePageOfDocument(); - const int encodedLen = MultiByteLenFromWideChar(codePage, characters); + const int encodedLen = MultiByteLenFromWideChar(CodePageOfDocument(), characters); if (encoded) { - MultiByteFromWideChar(codePage, characters, encoded, encodedLen); + MultiByteFromWideChar(CodePageOfDocument(), characters, encoded, encodedLen); encoded[encodedLen] = '\0'; } return encodedLen; @@ -1128,18 +948,14 @@ bool ScintillaWin::PaintDC(HDC hdc) { sptr_t ScintillaWin::WndPaint() { //ElapsedPeriod ep; - - // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - if (paintState != PaintState::notPainting) { return 0; } // prevent recursion loop - // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // Redirect assertions to debug output and save current state - //const bool assertsPopup = Platform::ShowAssertionPopUps(false); + const bool assertsPopup = Platform::ShowAssertionPopUps(false); paintState = PaintState::painting; PAINTSTRUCT ps = {}; // Removed since this interferes with reporting other assertions as it occurs repeatedly - //PLATFORM_ASSERT(hRgnUpdate == nullptr); + //PLATFORM_ASSERT(hRgnUpdate == NULL); hRgnUpdate = ::CreateRectRgn(0, 0, 0, 0); ::GetUpdateRgn(MainHWND(), hRgnUpdate, FALSE); ::BeginPaint(MainHWND(), &ps); @@ -1163,7 +979,7 @@ sptr_t ScintillaWin::WndPaint() { paintState = PaintState::notPainting; // Restore debug output state - //Platform::ShowAssertionPopUps(assertsPopup); + Platform::ShowAssertionPopUps(assertsPopup); //Platform::DebugPrintf("Paint took %g\n", ep.Duration()); return 0; @@ -1192,32 +1008,9 @@ bool ScintillaWin::KoreanIME() noexcept { return codePage == 949 || codePage == 1361; } -// >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> -bool ScintillaWin::IsIMEOpen() { - IMContext imc(MainHWND()); - if (imc.hIMC) { - if (ImmGetOpenStatus(imc.hIMC)) { - return true; - } - } - return false; -} - -DWORD ScintillaWin::GetIMEInputMode() { - IMContext imc(MainHWND()); - if (imc.hIMC && ImmGetOpenStatus(imc.hIMC)) { - DWORD dwConversion = IME_CMODE_ALPHANUMERIC, dwSentence = IME_SMODE_NONE; - if (ImmGetConversionStatus(imc.hIMC, &dwConversion, &dwSentence)) { - return dwConversion; - } - } - return 0; -} -// <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< - -void ScintillaWin::MoveImeCarets(Sci::Position offset) noexcept { +void ScintillaWin::MoveImeCarets(Sci::Position offset) { // Move carets relatively by bytes. - for (size_t r = 0; r < sel.Count(); r++) { + for (size_t r=0; rDecorationSetCurrentIndicator(indicator); - for (size_t r = 0; r < sel.Count(); r++) { + for (size_t r=0; rDecorationFillRange(positionInsert - len, 1, len); } @@ -1267,17 +1060,16 @@ void ScintillaWin::SelectionToHangul() { if (utf16Len > 0) { std::string documentStr(documentStrLen, '\0'); - pdoc->GetCharRange(documentStr.data(), selStart, documentStrLen); - const UINT codePage = CodePageOfDocument(); + pdoc->GetCharRange(&documentStr[0], selStart, documentStrLen); - std::wstring uniStr = StringDecode(documentStr, codePage); - const int converted = HanjaDict::GetHangulOfHanja(uniStr.data()); - documentStr = StringEncode(uniStr, codePage); + std::wstring uniStr = StringDecode(documentStr, CodePageOfDocument()); + const int converted = HanjaDict::GetHangulOfHanja(&uniStr[0]); + documentStr = StringEncode(uniStr, CodePageOfDocument()); if (converted > 0) { pdoc->BeginUndoAction(); ClearSelection(); - InsertPaste(documentStr.data(), documentStr.size()); + InsertPaste(&documentStr[0], documentStr.size()); pdoc->EndUndoAction(); } } @@ -1301,7 +1093,7 @@ void ScintillaWin::EscapeHanja() { // So enlarge it enough to Maximum 4 as in UTF-8. constexpr size_t safeLength = UTF8MaxBytes + 1; std::string oneChar(safeLength, '\0'); - pdoc->GetCharRange(oneChar.data(), currentPos, oneCharLen); + pdoc->GetCharRange(&oneChar[0], currentPos, oneCharLen); std::wstring uniChar = StringDecode(oneChar, CodePageOfDocument()); @@ -1310,7 +1102,7 @@ void ScintillaWin::EscapeHanja() { // Set the candidate box position since IME may show it. SetCandidateWindowPos(); // IME_ESC_HANJA_MODE appears to receive the first character only. - if (::ImmEscapeW(GetKeyboardLayout(0), imc.hIMC, IME_ESC_HANJA_MODE, uniChar.data())) { + if (::ImmEscapeW(GetKeyboardLayout(0), imc.hIMC, IME_ESC_HANJA_MODE, &uniChar[0])) { SetSelection(currentPos, currentPos + oneCharLen); } } @@ -1332,8 +1124,7 @@ void ScintillaWin::ToggleHanja() { namespace { -// https://docs.microsoft.com/en-us/windows/desktop/Intl/composition-string -std::vector MapImeIndicators(const std::vector &inputStyle) { +std::vector MapImeIndicators(std::vector inputStyle) { std::vector imeIndicator(inputStyle.size(), SC_INDICATOR_UNKNOWN); for (size_t i = 0; i < inputStyle.size(); i++) { switch (static_cast(inputStyle.at(i))) { @@ -1361,14 +1152,12 @@ void ScintillaWin::AddWString(std::wstring_view wsv, CharacterSource charSource) if (wsv.empty()) return; - const UINT codePage = CodePageOfDocument(); - char inBufferCP[16]; + const int codePage = CodePageOfDocument(); for (size_t i = 0; i < wsv.size(); ) { const size_t ucWidth = UTF16CharLength(wsv[i]); + const std::string docChar = StringEncode(wsv.substr(i, ucWidth), codePage); - const int size = MultiByteFromWideChar(codePage, wsv.substr(i, ucWidth), inBufferCP, sizeof(inBufferCP) - 1); - inBufferCP[size] = '\0'; - InsertCharacter(std::string_view(inBufferCP, size), charSource); + InsertCharacter(docChar, charSource); i += ucWidth; } } @@ -1417,29 +1206,44 @@ sptr_t ScintillaWin::HandleCompositionInline(uptr_t, sptr_t lParam) { std::vector imeIndicator = MapImeIndicators(imc.GetImeAttributes()); - const UINT codePage = CodePageOfDocument(); - char inBufferCP[16]; + const int codePage = CodePageOfDocument(); const std::wstring_view wsv = wcs; - for (size_t i = 0; i < wsv.size(); ) { const size_t ucWidth = UTF16CharLength(wsv[i]); - const int size = MultiByteFromWideChar(codePage, wsv.substr(i, ucWidth), inBufferCP, sizeof(inBufferCP) - 1); - inBufferCP[size] = '\0'; - InsertCharacter(std::string_view(inBufferCP, size), CharacterSource::tentativeInput); + const std::string docChar = StringEncode(wsv.substr(i, ucWidth), codePage); - DrawImeIndicator(imeIndicator[i], size); + InsertCharacter(docChar, CharacterSource::tentativeInput); + + DrawImeIndicator(imeIndicator[i], docChar.size()); i += ucWidth; } - // Move IME caret from current last position to imeCaretPos. - const int imeEndToImeCaretU16 = imc.GetImeCaretPos() - static_cast(wcs.size()); - const Sci::Position imeCaretPosDoc = pdoc->GetRelativePositionUTF16(CurrentPosition(), imeEndToImeCaretU16); + // Japanese IME after pressing Tab replaces input string with first candidate item (target string); + // when selecting other candidate item, previous item will be replaced with current one. + // After candidate item been added, it's looks like been full selected, it's better to keep caret + // at end of "selection" (end of input) instead of jump to beginning of input ("selection"). + const bool onlyTarget = std::all_of(imeIndicator.begin(), imeIndicator.end(), [](int i) noexcept { + return i == SC_INDICATOR_TARGET; + }); + if (!onlyTarget) { + // CS_NOMOVECARET: keep caret at beginning of composition string which already moved in InsertCharacter(). + // GCS_CURSORPOS: current caret position is provided by IME. + Sci::Position imeEndToImeCaretU16 = -static_cast(wcs.size()); + if (!(lParam & CS_NOMOVECARET) && (lParam & GCS_CURSORPOS)) { + imeEndToImeCaretU16 += imc.GetImeCaretPos(); + } + if (imeEndToImeCaretU16 != 0) { + // Move back IME caret from current last position to imeCaretPos. + const Sci::Position currentPos = CurrentPosition(); + const Sci::Position imeCaretPosDoc = pdoc->GetRelativePositionUTF16(currentPos, imeEndToImeCaretU16); - MoveImeCarets(-CurrentPosition() + imeCaretPosDoc); + MoveImeCarets(-currentPos + imeCaretPosDoc); - if (std::find(imeIndicator.begin(), imeIndicator.end(), SC_INDICATOR_TARGET) != imeIndicator.end()) { - // set candidate window left aligned to beginning of target string. - SetCandidateWindowPos(); + if (std::find(imeIndicator.begin(), imeIndicator.end(), SC_INDICATOR_TARGET) != imeIndicator.end()) { + // set candidate window left aligned to beginning of target string. + SetCandidateWindowPos(); + } + } } if (KoreanIME()) { @@ -1457,30 +1261,25 @@ namespace { unsigned int SciMessageFromEM(unsigned int iMessage) noexcept { switch (iMessage) { case EM_CANPASTE: return SCI_CANPASTE; - case EM_CANREDO: return SCI_CANREDO; case EM_CANUNDO: return SCI_CANUNDO; case EM_EMPTYUNDOBUFFER: return SCI_EMPTYUNDOBUFFER; case EM_FINDTEXTEX: return SCI_FINDTEXT; case EM_FORMATRANGE: return SCI_FORMATRANGE; case EM_GETFIRSTVISIBLELINE: return SCI_GETFIRSTVISIBLELINE; - case EM_GETLINE: return SCI_GETLINE; case EM_GETLINECOUNT: return SCI_GETLINECOUNT; case EM_GETSELTEXT: return SCI_GETSELTEXT; case EM_GETTEXTRANGE: return SCI_GETTEXTRANGE; case EM_HIDESELECTION: return SCI_HIDESELECTION; case EM_LINEINDEX: return SCI_POSITIONFROMLINE; case EM_LINESCROLL: return SCI_LINESCROLL; - case EM_REDO: return SCI_REDO; case EM_REPLACESEL: return SCI_REPLACESEL; - case EM_SCROLL: return WM_VSCROLL; case EM_SCROLLCARET: return SCI_SCROLLCARET; case EM_SETREADONLY: return SCI_SETREADONLY; - case EM_UNDO: return SCI_UNDO; case WM_CLEAR: return SCI_CLEAR; case WM_COPY: return SCI_COPY; case WM_CUT: return SCI_CUT; - case WM_PASTE: return SCI_PASTE; case WM_SETTEXT: return SCI_SETTEXT; + case WM_PASTE: return SCI_PASTE; case WM_UNDO: return SCI_UNDO; } return iMessage; @@ -1491,15 +1290,12 @@ unsigned int SciMessageFromEM(unsigned int iMessage) noexcept { namespace Scintilla { UINT CodePageFromCharSet(DWORD characterSet, UINT documentCodePage) noexcept { - // UTF-8 and DBCS ANSI code pages - if (documentCodePage) { - return SC_CP_UTF8; // we only use UTF-8 + if (documentCodePage == SC_CP_UTF8) { + return SC_CP_UTF8; } - // SBCS code pages: zero / CP_ACP switch (characterSet) { case SC_CHARSET_ANSI: return 1252; - //case SC_CHARSET_DEFAULT: return documentCodePage ? documentCodePage : 1252; // SCI orig - case SC_CHARSET_DEFAULT: return documentCodePage; + case SC_CHARSET_DEFAULT: return documentCodePage ? documentCodePage : 1252; case SC_CHARSET_BALTIC: return 1257; case SC_CHARSET_CHINESEBIG5: return 950; case SC_CHARSET_EASTEUROPE: return 1250; @@ -1517,7 +1313,7 @@ UINT CodePageFromCharSet(DWORD characterSet, UINT documentCodePage) noexcept { case SC_CHARSET_VIETNAMESE: return 1258; case SC_CHARSET_THAI: return 874; case SC_CHARSET_8859_15: return 28605; - // Not supported + // Not supported case SC_CHARSET_CYRILLIC: return documentCodePage; case SC_CHARSET_SYMBOL: return documentCodePage; } @@ -1527,8 +1323,7 @@ UINT CodePageFromCharSet(DWORD characterSet, UINT documentCodePage) noexcept { } UINT ScintillaWin::CodePageOfDocument() const noexcept { - return pdoc->dbcsCodePage; // see SCI_GETCODEPAGE in Editor.cxx - //return CodePageFromCharSet(vs.styles[STYLE_DEFAULT].characterSet, pdoc->dbcsCodePage); + return CodePageFromCharSet(vs.styles[STYLE_DEFAULT].characterSet, pdoc->dbcsCodePage); } std::string ScintillaWin::EncodeWString(std::wstring_view wsv) { @@ -1543,11 +1338,11 @@ std::string ScintillaWin::EncodeWString(std::wstring_view wsv) { } } -sptr_t ScintillaWin::GetTextLength() const noexcept { +sptr_t ScintillaWin::GetTextLength() { return pdoc->CountUTF16(0, pdoc->Length()); } -sptr_t ScintillaWin::GetText(uptr_t wParam, sptr_t lParam) const { +sptr_t ScintillaWin::GetText(uptr_t wParam, sptr_t lParam) { if (lParam == 0) { return pdoc->CountUTF16(0, pdoc->Length()); } @@ -1605,13 +1400,14 @@ Window::Cursor ScintillaWin::ContextCursor(Point pt) { return Window::Cursor::text; } +// >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> +#if SCI_EnablePopupMenu sptr_t ScintillaWin::ShowContextMenu(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { Point pt = PointFromLParam(lParam); POINT rpt = POINTFromPoint(pt); ::ScreenToClient(MainHWND(), &rpt); const Point ptClient = PointFromPOINT(rpt); if (ShouldDisplayPopup(ptClient)) { -#if SCI_EnablePopupMenu if ((pt.x == -1) && (pt.y == -1)) { // Caused by keyboard so display menu near caret pt = PointMainCaret(); @@ -1621,16 +1417,11 @@ sptr_t ScintillaWin::ShowContextMenu(unsigned int iMessage, uptr_t wParam, sptr_ } ContextMenu(pt); return 0; -#else - return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); -#endif } -#if SCI_EnablePopupMenu return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); -#else - return 0; -#endif } +#endif +// <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< void ScintillaWin::SizeWindow() { #if defined(USE_D2D) @@ -1669,37 +1460,28 @@ sptr_t ScintillaWin::MouseMessage(unsigned int iMessage, uptr_t wParam, sptr_t l break; case WM_RBUTTONDOWN: { - ::SetFocus(MainHWND()); - const Point pt = PointFromLParam(lParam); - if (!PointInSelection(pt)) { - CancelModes(); - SetEmptySelection(PositionFromLocation(PointFromLParam(lParam))); - } + ::SetFocus(MainHWND()); + const Point pt = PointFromLParam(lParam); + if (!PointInSelection(pt)) { + CancelModes(); + SetEmptySelection(PositionFromLocation(PointFromLParam(lParam))); + } RightButtonDownWithModifiers(pt, ::GetMessageTime(), MouseModifiers(wParam)); } break; - // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> - case WM_MBUTTONDOWN: - // send to main window - ::SetFocus(MainHWND()); - //::DefWindowProc(MainHWND(), iMessage, wParam, lParam); // does not propagate - filter msg ? - ::SendMessage(GetParent(MainHWND()), WM_MBUTTONDOWN, wParam, lParam); - break; - // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< - case WM_MOUSEMOVE: { - const Point pt = PointFromLParam(lParam); + const Point pt = PointFromLParam(lParam); - // Windows might send WM_MOUSEMOVE even though the mouse has not been moved: - // http://blogs.msdn.com/b/oldnewthing/archive/2003/10/01/55108.aspx - if (ptMouseLast != pt) { - SetTrackMouseLeaveEvent(true); - ButtonMoveWithModifiers(pt, ::GetMessageTime(), MouseModifiers(wParam)); + // Windows might send WM_MOUSEMOVE even though the mouse has not been moved: + // http://blogs.msdn.com/b/oldnewthing/archive/2003/10/01/55108.aspx + if (ptMouseLast != pt) { + SetTrackMouseLeaveEvent(true); + ButtonMoveWithModifiers(pt, ::GetMessageTime(), MouseModifiers(wParam)); + } } - } - break; + break; case WM_MOUSELEAVE: SetTrackMouseLeaveEvent(false); @@ -1714,11 +1496,9 @@ sptr_t ScintillaWin::MouseMessage(unsigned int iMessage, uptr_t wParam, sptr_t l RECT rc; GetWindowRect(MainHWND(), &rc); const POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; - if (!PtInRect(&rc, pt)) { + if (!PtInRect(&rc, pt)) return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); - } } - // if autocomplete list active then send mousewheel message to it if (ac.Active()) { HWND hWnd = HwndFromWindow(*(ac.lb)); @@ -1730,46 +1510,23 @@ sptr_t ScintillaWin::MouseMessage(unsigned int iMessage, uptr_t wParam, sptr_t l // (A good idea for datazoom would be to "fold" or "unfold" details. // i.e. if datazoomed out only class structures are visible, when datazooming in the control // structures appear, then eventually the individual statements...) - //@@@if (wParam & (MK_SHIFT | MK_RBUTTON)) { if (wParam & MK_SHIFT) { - if (vs.wrapState != WrapMode::none || charsPerScroll == 0) { - return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); - } + return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); } - // Either SCROLL or ZOOM. We handle the wheel steppings calculation wheelDelta -= GET_WHEEL_DELTA_WPARAM(wParam); - if (std::abs(wheelDelta) < WHEEL_DELTA) { - return 0; - } - if (wParam & MK_SHIFT) { - int charsToScroll = charsPerScroll; - if (charsPerScroll == WHEEL_PAGESCROLL) { - const PRectangle rcText = GetTextRectangle(); - const int pageWidth = static_cast(rcText.Width() * 2 / 3); - charsToScroll = pageWidth; - } else { - charsToScroll = 1 + static_cast(std::max(charsToScroll, 1) * vs.aveCharWidth); - } - charsToScroll *= (wheelDelta / WHEEL_DELTA); - if (wheelDelta >= 0) { - wheelDelta = wheelDelta % WHEEL_DELTA; - } else { - wheelDelta = -(-wheelDelta % WHEEL_DELTA); - } - HorizontalScrollTo(xOffset + charsToScroll); - } else if (linesPerScroll > 0) { + if (std::abs(wheelDelta) >= WHEEL_DELTA && linesPerScroll > 0) { Sci::Line linesToScroll = linesPerScroll; - if (linesPerScroll == WHEEL_PAGESCROLL) { + if (linesPerScroll == WHEEL_PAGESCROLL) linesToScroll = LinesOnScreen() - 1; + if (linesToScroll == 0) { + linesToScroll = 1; } - linesToScroll = std::max(linesToScroll, 1); linesToScroll *= (wheelDelta / WHEEL_DELTA); - if (wheelDelta >= 0) { + if (wheelDelta >= 0) wheelDelta = wheelDelta % WHEEL_DELTA; - } else { + else wheelDelta = -(-wheelDelta % WHEEL_DELTA); - } if (wParam & MK_CONTROL) { // Zoom! We play with the font sizes in the styles. @@ -1779,57 +1536,12 @@ sptr_t ScintillaWin::MouseMessage(unsigned int iMessage, uptr_t wParam, sptr_t l } else { KeyCommand(SCI_ZOOMOUT); } - // send to main window too (trigger Zoom CallTip) ! - ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); } else { // Scroll ScrollTo(topLine + linesToScroll); } } return 0; - - case WM_MOUSEHWHEEL: - if (!mouseWheelCaptures) { - // if the mouse wheel is not captured, test if the mouse - // pointer is over the editor window and if not, don't - // handle the message but pass it on. - RECT rc; - GetWindowRect(MainHWND(), &rc); - const POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; - if (!PtInRect(&rc, pt)) { - return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); - } - } - - wheelDeltaH += GET_WHEEL_DELTA_WPARAM(wParam); - if (std::abs(wheelDeltaH) < WHEEL_DELTA) { - return 0; - } - - if (vs.wrapState != WrapMode::none || charsPerScroll == 0) { - return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); - } - else { - int charsToScroll = charsPerScroll; - if (charsPerScroll == WHEEL_PAGESCROLL) { - const PRectangle rcText = GetTextRectangle(); - const int pageWidth = static_cast(rcText.Width() * 2 / 3); - charsToScroll = pageWidth; - } - else { - charsToScroll = 1 + static_cast(std::max(charsToScroll, 1) * vs.aveCharWidth); - } - charsToScroll *= (wheelDeltaH / WHEEL_DELTA); - if (wheelDeltaH >= 0) { - wheelDeltaH = wheelDeltaH % WHEEL_DELTA; - } - else { - wheelDeltaH = -(-wheelDeltaH % WHEEL_DELTA); - } - HorizontalScrollTo(xOffset + charsToScroll); - } - return 0; - } return 0; } @@ -1839,34 +1551,36 @@ sptr_t ScintillaWin::KeyMessage(unsigned int iMessage, uptr_t wParam, sptr_t lPa case WM_SYSKEYDOWN: case WM_KEYDOWN: { - // Platform::DebugPrintf("Keydown %c %c%c%c%c %x %x\n", - // iMessage == WM_KEYDOWN ? 'K' : 'S', - // (lParam & (1 << 24)) ? 'E' : '-', - // KeyboardIsKeyDown(VK_SHIFT) ? 'S' : '-', - // KeyboardIsKeyDown(VK_CONTROL) ? 'C' : '-', - // KeyboardIsKeyDown(VK_MENU) ? 'A' : '-', - // wParam, lParam); - lastKeyDownConsumed = false; - const bool altDown = KeyboardIsKeyDown(VK_MENU); - if (altDown && KeyboardIsNumericKeypadFunction(wParam, lParam)) { - // Don't interpret these as they may be characters entered by number. - return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); + // Platform::DebugPrintf("Keydown %c %c%c%c%c %x %x\n", + // iMessage == WM_KEYDOWN ? 'K' : 'S', + // (lParam & (1 << 24)) ? 'E' : '-', + // KeyboardIsKeyDown(VK_SHIFT) ? 'S' : '-', + // KeyboardIsKeyDown(VK_CONTROL) ? 'C' : '-', + // KeyboardIsKeyDown(VK_MENU) ? 'A' : '-', + // wParam, lParam); + lastKeyDownConsumed = false; + const bool altDown = KeyboardIsKeyDown(VK_MENU); + if (altDown && KeyboardIsNumericKeypadFunction(wParam, lParam)) { + // Don't interpret these as they may be characters entered by number. + return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); + } + const int ret = KeyDownWithModifiers(KeyTranslate(static_cast(wParam)), + ModifierFlags(KeyboardIsKeyDown(VK_SHIFT), + KeyboardIsKeyDown(VK_CONTROL), + altDown), + &lastKeyDownConsumed); + if (!ret && !lastKeyDownConsumed) { + return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); + } + break; } - const int ret = KeyDownWithModifiers(KeyTranslate(static_cast(wParam)), - ModifierFlags(KeyboardIsKeyDown(VK_SHIFT), KeyboardIsKeyDown(VK_CONTROL), altDown), - &lastKeyDownConsumed); - if (!ret && !lastKeyDownConsumed) { - return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); - } - break; - } case WM_KEYUP: //Platform::DebugPrintf("S keyup %d %x %x\n",iMessage, wParam, lParam); return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); case WM_CHAR: - if (!lastKeyDownConsumed) { + if (((wParam >= 128) || !iscntrl(static_cast(wParam))) || !lastKeyDownConsumed) { wchar_t wcs[3] = { static_cast(wParam), 0 }; unsigned int wclen = 1; if (IS_HIGH_SURROGATE(wcs[0])) { @@ -1904,7 +1618,7 @@ sptr_t ScintillaWin::FocusMessage(unsigned int iMessage, uptr_t wParam, sptr_t) case WM_KILLFOCUS: { HWND wOther = reinterpret_cast(wParam); HWND wThis = MainHWND(); - HWND wCT = HwndFromWindow(ct.wCallTip); + const HWND wCT = HwndFromWindow(ct.wCallTip); if (!wParam || !(::IsChild(wThis, wOther) || (wOther == wCT))) { SetFocusState(false); @@ -1937,18 +1651,18 @@ sptr_t ScintillaWin::IMEMessage(unsigned int iMessage, uptr_t wParam, sptr_t lPa return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); case WM_IME_KEYDOWN: { - if (wParam == VK_HANJA) { - ToggleHanja(); + if (wParam == VK_HANJA) { + ToggleHanja(); + } + return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); } - return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); - } case WM_IME_REQUEST: { - if (wParam == IMR_RECONVERTSTRING) { - return ImeOnReconvert(lParam); + if (wParam == IMR_RECONVERTSTRING) { + return ImeOnReconvert(lParam); + } + return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); } - return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); - } case WM_IME_STARTCOMPOSITION: if (KoreanIME() || imeInteraction == IMEInteraction::internal) { @@ -1979,65 +1693,16 @@ sptr_t ScintillaWin::IMEMessage(unsigned int iMessage, uptr_t wParam, sptr_t lPa } return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); - // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> case WM_IME_NOTIFY: - if (wParam == IMN_SETOPENSTATUS) { - imeIsOpen = IsIMEOpen(); - } - if (wParam == IMN_SETOPENSTATUS || wParam == IMN_SETCONVERSIONMODE) { - imeIsInModeCJK = (GetIMEInputMode() != IME_CMODE_ALPHANUMERIC); - } return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); - // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< -} + } return 0; } sptr_t ScintillaWin::EditMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { switch (iMessage) { - case EM_FINDTEXT: - if (lParam == 0) { - return -1; - } else { - const FINDTEXTA *pFT = reinterpret_cast(lParam); - Sci_TextToFind tt = { { pFT->chrg.cpMin, pFT->chrg.cpMax }, pFT->lpstrText, {} }; - return ScintillaBase::WndProc(SCI_FINDTEXT, wParam, reinterpret_cast(&tt)); - } - - case EM_FINDTEXTEX: - if (lParam == 0) { - return -1; - } else { - FINDTEXTEXA *pFT = reinterpret_cast(lParam); - Sci_TextToFind tt = { { pFT->chrg.cpMin, pFT->chrg.cpMax }, pFT->lpstrText, {} }; - const Sci::Position pos =ScintillaBase::WndProc(SCI_FINDTEXT, wParam, reinterpret_cast(&tt)); - pFT->chrgText.cpMin = (pos == -1)? -1 : static_cast(tt.chrgText.cpMin); - pFT->chrgText.cpMax = (pos == -1)? -1 : static_cast(tt.chrgText.cpMax); - return pos; - } - - case EM_FORMATRANGE: - if (lParam) { - const FORMATRANGE *pFR = reinterpret_cast(lParam); - const Sci_RangeToFormat fr = { pFR->hdcTarget, pFR->hdc, - { pFR->rc.left, pFR->rc.top, pFR->rc.right, pFR->rc.bottom }, - { pFR->rcPage.left, pFR->rcPage.top, pFR->rcPage.right, pFR->rcPage.bottom }, - { pFR->chrg.cpMin, pFR->chrg.cpMax }, - }; - return ScintillaBase::WndProc(SCI_FORMATRANGE, wParam, reinterpret_cast(&fr)); - } - break; - - case EM_GETTEXTRANGE: - if (lParam) { - TEXTRANGEA *pTR = reinterpret_cast(lParam); - Sci_TextRange tr = { { pTR->chrg.cpMin, pTR->chrg.cpMax }, pTR->lpstrText }; - return ScintillaBase::WndProc(SCI_GETTEXTRANGE, 0, reinterpret_cast(&tr)); - } - break; - case EM_LINEFROMCHAR: if (static_cast(wParam) < 0) { wParam = SelectionStart().Position(); @@ -2057,78 +1722,43 @@ sptr_t ScintillaWin::EditMessage(unsigned int iMessage, uptr_t wParam, sptr_t lP return MAKELRESULT(SelectionStart().Position(), SelectionEnd().Position()); case EM_EXGETSEL: { - if (lParam == 0) { - return 0; + if (lParam == 0) { + return 0; + } + CHARRANGE *pCR = reinterpret_cast(lParam); + pCR->cpMin = static_cast(SelectionStart().Position()); + pCR->cpMax = static_cast(SelectionEnd().Position()); } - CHARRANGE *pCR = reinterpret_cast(lParam); - pCR->cpMin = static_cast(SelectionStart().Position()); - pCR->cpMax = static_cast(SelectionEnd().Position()); - } - break; + break; case EM_SETSEL: { - Sci::Position nStart = wParam; - Sci::Position nEnd = lParam; - if (nStart == 0 && nEnd == -1) { - nEnd = pdoc->Length(); + Sci::Position nStart = wParam; + Sci::Position nEnd = lParam; + if (nStart == 0 && nEnd == -1) { + nEnd = pdoc->Length(); + } + if (nStart == -1) { + nStart = nEnd; // Remove selection + } + SetSelection(nEnd, nStart); + EnsureCaretVisible(); } - if (nStart == -1) { - nStart = nEnd; // Remove selection - } - SetSelection(nEnd, nStart); - EnsureCaretVisible(); - } - break; + break; case EM_EXSETSEL: { - if (lParam == 0) { - return 0; + if (lParam == 0) { + return 0; + } + const CHARRANGE *pCR = reinterpret_cast(lParam); + sel.selType = Selection::SelTypes::stream; + if (pCR->cpMin == 0 && pCR->cpMax == -1) { + SetSelection(pCR->cpMin, pdoc->Length()); + } else { + SetSelection(pCR->cpMin, pCR->cpMax); + } + EnsureCaretVisible(); + return pdoc->LineFromPosition(SelectionStart().Position()); } - const CHARRANGE *pCR = reinterpret_cast(lParam); - sel.selType = Selection::SelTypes::stream; - if (pCR->cpMin == 0 && pCR->cpMax == -1) { - SetSelection(pCR->cpMin, pdoc->Length()); - } else { - SetSelection(pCR->cpMin, pCR->cpMax); - } - EnsureCaretVisible(); - return pdoc->LineFromPosition(SelectionStart().Position()); - } - - case EM_LINELENGTH: - return ScintillaBase::WndProc(SCI_LINELENGTH, pdoc->LineFromPosition(wParam), lParam); - - case EM_POSFROMCHAR: - if (wParam) { - const Point pt = LocationFromPosition(lParam); - POINTL *ptw = reinterpret_cast(wParam); - ptw->x = static_cast(pt.x - vs.textStart + vs.fixedColumnWidth); // SCI_POINTXFROMPOSITION - ptw->y = static_cast(pt.y); - } - break; - - case EM_GETZOOM: - if (wParam && lParam) { - *reinterpret_cast(wParam) = 16*vs.zoomLevel/25; - *reinterpret_cast(lParam) = 64; - return TRUE; - } - break; - - case EM_SETZOOM: { - int level = 0; - if (wParam == 0 && lParam == 0) { - level = 100; - } else if (wParam != 0 && lParam > 0) { - level = static_cast(wParam/lParam); - } - if (level != 0) { - ScintillaBase::WndProc(SCI_SETZOOM, level, 0); - return TRUE; - } - } - break; - } return 0; } @@ -2150,15 +1780,15 @@ sptr_t ScintillaWin::IdleMessage(unsigned int iMessage, uptr_t wParam, sptr_t lP // Suppress a warning from Code Analysis that the GetTickCount function // wraps after 49 days. The WM_TIMER will kick off another SC_WIN_IDLE // after the wrap. - - #pragma warning( disable : 28159 ) +#ifdef _MSC_VER +#pragma warning(suppress: 28159) +#endif const DWORD dwCurrent = GetTickCount(); const DWORD dwStart = wParam ? static_cast(wParam) : dwCurrent; constexpr DWORD maxWorkTime = 50; - if (dwCurrent >= dwStart && dwCurrent > maxWorkTime &&dwCurrent - maxWorkTime < dwStart) { + if (dwCurrent >= dwStart && dwCurrent > maxWorkTime &&dwCurrent - maxWorkTime < dwStart) PostMessage(MainHWND(), SC_WIN_IDLE, dwStart, 0); - } } else { SetIdle(false); } @@ -2200,7 +1830,7 @@ sptr_t ScintillaWin::SciMessage(unsigned int iMessage, uptr_t wParam, sptr_t lPa (wParam == SC_TECHNOLOGY_DIRECTWRITE)) { const int technologyNew = static_cast(wParam); if (technology != technologyNew) { - if (technologyNew != SC_TECHNOLOGY_DEFAULT) { + if (technologyNew > SC_TECHNOLOGY_DEFAULT) { #if defined(USE_D2D) if (!LoadD2D()) // Failed to load Direct2D or DirectWrite so no effect @@ -2213,11 +1843,9 @@ sptr_t ScintillaWin::SciMessage(unsigned int iMessage, uptr_t wParam, sptr_t lPa } #if defined(USE_D2D) DropRenderTarget(); - view.bufferedDraw = technologyNew == SC_TECHNOLOGY_DEFAULT; #endif technology = technologyNew; // Invalidate all cached information including layout. - vs.fontsValid = false; DropGraphics(); InvalidateStyleRedraw(); } @@ -2267,13 +1895,13 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam return WndPaint(); case WM_PRINTCLIENT: { - HDC hdc = reinterpret_cast(wParam); - if (!IsCompatibleDC(hdc)) { - return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); + HDC hdc = reinterpret_cast(wParam); + if (!IsCompatibleDC(hdc)) { + return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); + } + FullPaintDC(hdc); } - FullPaintDC(hdc); - } - break; + break; case WM_VSCROLL: ScrollMessage(wParam); @@ -2305,11 +1933,9 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONDOWN: - case WM_MBUTTONDOWN: case WM_MOUSEMOVE: case WM_MOUSELEAVE: case WM_MOUSEWHEEL: - case WM_MOUSEHWHEEL: return MouseMessage(iMessage, wParam, lParam); case WM_SETCURSOR: @@ -2320,8 +1946,9 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam DisplayCursor(ContextCursor(PointFromPOINT(pt))); } return TRUE; + } else { + return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); } - return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); case WM_SYSKEYDOWN: case WM_KEYDOWN: @@ -2350,24 +1977,25 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam break; case WM_DPICHANGED: - dpi.x = LOWORD(wParam); - dpi.y = HIWORD(wParam); - vs.fontsValid = false; + dpi = HIWORD(wParam); InvalidateStyleRedraw(); break; case WM_DPICHANGED_AFTERPARENT: { - DPI_T const dpiNow = GetWindowDPI(MainHWND()); - if ((dpi.x != dpiNow.x) || (dpi.y != dpiNow.y)) { - dpi = dpiNow; - vs.fontsValid = false; - InvalidateStyleRedraw(); + const UINT dpiNow = DpiForWindow(wMain.GetID()); + if (dpi != dpiNow) { + dpi = dpiNow; + InvalidateStyleRedraw(); + } } - } - break; + break; + // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> + #if SCI_EnablePopupMenu case WM_CONTEXTMENU: return ShowContextMenu(iMessage, wParam, lParam); + #endif + // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< case WM_ERASEBKGND: return 1; // Avoid any background erasure as whole window painted. @@ -2410,18 +2038,10 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam case EM_LINEFROMCHAR: case EM_EXLINEFROMCHAR: - case EM_FINDTEXT: - case EM_FINDTEXTEX: - case EM_FORMATRANGE: - case EM_GETTEXTRANGE: case EM_GETSEL: case EM_EXGETSEL: case EM_SETSEL: case EM_EXSETSEL: - case EM_LINELENGTH: - case EM_POSFROMCHAR: - case EM_GETZOOM: - case EM_SETZOOM: return EditMessage(iMessage, wParam, lParam); case SCI_GETDIRECTFUNCTION: @@ -2448,10 +2068,10 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam return 0; } -bool ScintillaWin::ValidCodePage(int codePage) const noexcept { +bool ScintillaWin::ValidCodePage(int codePage) const { return codePage == 0 || codePage == SC_CP_UTF8 || - codePage == 932 || codePage == 936 || codePage == 949 || - codePage == 950 || codePage == 1361; + codePage == 932 || codePage == 936 || codePage == 949 || + codePage == 950 || codePage == 1361; } std::string ScintillaWin::UTF8FromEncoded(std::string_view encoded) const { @@ -2474,34 +2094,26 @@ std::string ScintillaWin::EncodedFromUTF8(std::string_view utf8) const { } } -sptr_t ScintillaWin::DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) noexcept { +sptr_t ScintillaWin::DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); } -bool ScintillaWin::FineTickerRunning(TickReason reason) noexcept { +bool ScintillaWin::FineTickerRunning(TickReason reason) { return timers[static_cast(reason)] != 0; } -void ScintillaWin::FineTickerStart(TickReason reason, int millis, int tolerance) noexcept { +void ScintillaWin::FineTickerStart(TickReason reason, int millis, int tolerance) { FineTickerCancel(reason); const UINT_PTR reasonIndex = static_cast(reason); const UINT_PTR eventID = static_cast(fineTimerStart) + reasonIndex; -#if _WIN32_WINNT < _WIN32_WINNT_WIN8 if (SetCoalescableTimerFn && tolerance) { timers[reasonIndex] = SetCoalescableTimerFn(MainHWND(), eventID, millis, nullptr, tolerance); } else { timers[reasonIndex] = ::SetTimer(MainHWND(), eventID, millis, nullptr); } -#else - if (tolerance) { - timers[reason] = ::SetCoalescableTimer(MainHWND(), eventID, millis, nullptr, tolerance); - } else { - timers[reason] = ::SetTimer(MainHWND(), eventID, millis, nullptr); - } -#endif } -void ScintillaWin::FineTickerCancel(TickReason reason) noexcept { +void ScintillaWin::FineTickerCancel(TickReason reason) { const UINT_PTR reasonIndex = static_cast(reason); if (timers[reasonIndex]) { ::KillTimer(MainHWND(), timers[reasonIndex]); @@ -2509,19 +2121,20 @@ void ScintillaWin::FineTickerCancel(TickReason reason) noexcept { } } -bool ScintillaWin::SetIdle(bool on) noexcept { + +bool ScintillaWin::SetIdle(bool on) { // On Win32 the Idler is implemented as a Timer on the Scintilla window. This // takes advantage of the fact that WM_TIMER messages are very low priority, // and are only posted when the message queue is empty, i.e. during idle time. if (idler.state != on) { if (on) { idler.idlerID = ::SetTimer(MainHWND(), idleTimerID, 10, nullptr) - ? reinterpret_cast(idleTimerID) : nullptr; + ? reinterpret_cast(idleTimerID) : 0; } else { ::KillTimer(MainHWND(), reinterpret_cast(idler.idlerID)); - idler.idlerID = nullptr; + idler.idlerID = 0; } - idler.state = idler.idlerID != nullptr; + idler.state = idler.idlerID != 0; } return idler.state; } @@ -2531,7 +2144,7 @@ void ScintillaWin::IdleWork() { Editor::IdleWork(); } -void ScintillaWin::QueueIdleWork(WorkItems items, Sci::Position upTo) noexcept { +void ScintillaWin::QueueIdleWork(WorkItems items, Sci::Position upTo) { Editor::QueueIdleWork(items, upTo); if (!styleIdleInQueue) { if (PostMessage(MainHWND(), SC_WORK_IDLE, 0, 0)) { @@ -2540,7 +2153,7 @@ void ScintillaWin::QueueIdleWork(WorkItems items, Sci::Position upTo) noexcept { } } -void ScintillaWin::SetMouseCapture(bool on) noexcept { +void ScintillaWin::SetMouseCapture(bool on) { if (mouseDownCaptures) { if (on) { ::SetCapture(MainHWND()); @@ -2551,7 +2164,7 @@ void ScintillaWin::SetMouseCapture(bool on) noexcept { capturedMouse = on; } -bool ScintillaWin::HaveMouseCapture() noexcept { +bool ScintillaWin::HaveMouseCapture() { // Cannot just see if GetCapture is this window as the scroll bar also sets capture for the window return capturedMouse; //return capturedMouse && (::GetCapture() == MainHWND()); @@ -2585,7 +2198,7 @@ void ScintillaWin::ScrollText(Sci::Line /* linesToMove */) { UpdateSystemCaret(); } -void ScintillaWin::NotifyCaretMove() noexcept { +void ScintillaWin::NotifyCaretMove() { NotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, MainHWND(), OBJID_CARET, CHILDID_SELF); } @@ -2605,12 +2218,12 @@ void ScintillaWin::UpdateSystemCaret() { } } -int ScintillaWin::SetScrollInfo(int nBar, LPCSCROLLINFO lpsi, BOOL bRedraw) const noexcept { +int ScintillaWin::SetScrollInfo(int nBar, LPCSCROLLINFO lpsi, BOOL bRedraw) noexcept { return ::SetScrollInfo(MainHWND(), nBar, lpsi, bRedraw); } -bool ScintillaWin::GetScrollInfo(int nBar, LPSCROLLINFO lpsi) const noexcept { - return ::GetScrollInfo(MainHWND(), nBar, lpsi) != 0; +bool ScintillaWin::GetScrollInfo(int nBar, LPSCROLLINFO lpsi) noexcept { + return ::GetScrollInfo(MainHWND(), nBar, lpsi) ? true : false; } // Change the scroll position but avoid repaint if changing to same value @@ -2647,8 +2260,8 @@ bool ScintillaWin::ModifyScrollBars(Sci::Line nMax, Sci::Line nPage) { nPage = vertEndPreferred + 1; if ((sci.nMin != 0) || (sci.nMax != vertEndPreferred) || - (sci.nPage != static_cast(nPage)) || - (sci.nPos != 0)) { + (sci.nPage != static_cast(nPage)) || + (sci.nPos != 0)) { sci.fMask = SIF_PAGE | SIF_RANGE; sci.nMin = 0; sci.nMax = static_cast(vertEndPreferred); @@ -2671,7 +2284,7 @@ bool ScintillaWin::ModifyScrollBars(Sci::Line nMax, Sci::Line nPage) { if ((sci.nMin != 0) || (sci.nMax != horizEndPreferred) || (sci.nPage != static_cast(pageWidth)) || - (sci.nPos != 0)) { + (sci.nPos != 0)) { sci.fMask = SIF_PAGE | SIF_RANGE; sci.nMin = 0; sci.nMax = horizEndPreferred; @@ -2687,9 +2300,9 @@ bool ScintillaWin::ModifyScrollBars(Sci::Line nMax, Sci::Line nPage) { return modified; } -void ScintillaWin::NotifyChange() noexcept { +void ScintillaWin::NotifyChange() { ::SendMessage(::GetParent(MainHWND()), WM_COMMAND, - MAKEWPARAM(GetCtrlID(), SCEN_CHANGE), + MAKEWPARAM(GetCtrlID(), SCEN_CHANGE), reinterpret_cast(MainHWND())); } @@ -2702,7 +2315,7 @@ void ScintillaWin::NotifyFocus(bool focus) { Editor::NotifyFocus(focus); } -void ScintillaWin::SetCtrlID(int identifier) noexcept { +void ScintillaWin::SetCtrlID(int identifier) { ::SetWindowID(HwndFromWindow(wMain), identifier); } @@ -2710,39 +2323,33 @@ int ScintillaWin::GetCtrlID() const noexcept { return ::GetDlgCtrlID(HwndFromWindow(wMain)); } -void ScintillaWin::NotifyParent(SCNotification scn) noexcept { +void ScintillaWin::NotifyParent(SCNotification scn) { scn.nmhdr.hwndFrom = MainHWND(); scn.nmhdr.idFrom = GetCtrlID(); ::SendMessage(::GetParent(MainHWND()), WM_NOTIFY, - GetCtrlID(), reinterpret_cast(&scn)); + GetCtrlID(), reinterpret_cast(&scn)); } void ScintillaWin::NotifyDoubleClick(Point pt, int modifiers) { //Platform::DebugPrintf("ScintillaWin Double click 0\n"); ScintillaBase::NotifyDoubleClick(pt, modifiers); // Send myself a WM_LBUTTONDBLCLK, so the container can handle it too. - ::SendMessage(::GetParent(MainHWND()), - WM_LBUTTONDBLCLK, - (modifiers & SCI_SHIFT) ? MK_SHIFT : 0, - MAKELPARAM(pt.x, pt.y)); + ::SendMessage(MainHWND(), + WM_LBUTTONDBLCLK, + (modifiers & SCI_SHIFT) ? MK_SHIFT : 0, + MAKELPARAM(pt.x, pt.y)); } -void ScintillaWin::NotifyURIDropped(const char *list) noexcept { - SCNotification scn = {}; - scn.nmhdr.code = SCN_URIDROPPED; - scn.text = list; - - NotifyParent(scn); -} - -class CaseFolderDBCS final : public CaseFolderTable { +class CaseFolderDBCS : public CaseFolderTable { // Allocate the expandable storage here so that it does not need to be reallocated // for each call to Fold. std::vector utf16Mixed; std::vector utf16Folded; UINT cp; public: - explicit CaseFolderDBCS(UINT cp_) noexcept : cp(cp_) { } + explicit CaseFolderDBCS(UINT cp_) : cp(cp_) { + StandardASCII(); + } size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) override { if ((lenMixed == 1) && (sizeFolded > 0)) { folded[0] = mapping[static_cast(mixed[0])]; @@ -2753,7 +2360,7 @@ public: } const size_t nUtf16Mixed = WideCharFromMultiByte(cp, std::string_view(mixed, lenMixed), - utf16Mixed.data(), + &utf16Mixed[0], utf16Mixed.size()); if (nUtf16Mixed == 0) { @@ -2763,7 +2370,7 @@ public: } size_t lenFlat = 0; - for (size_t mixIndex = 0; mixIndex < nUtf16Mixed; mixIndex++) { + for (size_t mixIndex=0; mixIndex < nUtf16Mixed; mixIndex++) { if ((lenFlat + 20) > utf16Folded.size()) utf16Folded.resize(lenFlat + 60); const char *foldedUTF8 = CaseConvert(utf16Mixed[mixIndex], CaseConversion::fold); @@ -2771,16 +2378,15 @@ public: // Maximum length of a case conversion is 6 bytes, 3 characters wchar_t wFolded[20]; const size_t charsConverted = UTF16FromUTF8(std::string_view(foldedUTF8), - wFolded, std::size(wFolded)); - for (size_t j = 0; j < charsConverted; j++) { + wFolded, std::size(wFolded)); + for (size_t j=0; j ScintillaWin::CaseFolderForEncoding() { std::unique_ptr pcf = std::make_unique(); pcf->StandardASCII(); // Only for single byte encodings - for (int i = 0x80; i < 0x100; i++) { + for (int i=0x80; i<0x100; i++) { char sCharacter[2] = "A"; sCharacter[0] = static_cast(i); wchar_t wCharacter[20]; @@ -2834,7 +2440,7 @@ std::unique_ptr ScintillaWin::CaseFolderForEncoding() { } std::string ScintillaWin::CaseMapString(const std::string &s, CaseMapping caseMapping) { - if ((s.empty()) || (caseMapping == CaseMapping::same)) + if ((s.size() == 0) || (caseMapping == CaseMapping::same)) return s; const UINT cpDoc = CodePageOfDocument(); @@ -2857,20 +2463,19 @@ std::string ScintillaWin::CaseMapString(const std::string &s, CaseMapping caseMa return sConverted; } -void ScintillaWin::Copy(bool asBinary) { +void ScintillaWin::Copy() { //Platform::DebugPrintf("Copy\n"); if (!sel.Empty()) { SelectionText selectedText; - selectedText.asBinary = asBinary; CopySelectionRange(&selectedText); CopyToClipboard(selectedText); } } -bool ScintillaWin::CanPaste() noexcept { +bool ScintillaWin::CanPaste() { if (!Editor::CanPaste()) return false; - return ::IsClipboardFormatAvailable(CF_UNICODETEXT); + return ::IsClipboardFormatAvailable(CF_UNICODETEXT) != FALSE; } namespace { @@ -2879,7 +2484,8 @@ class GlobalMemory { HGLOBAL hand {}; public: void *ptr {}; - GlobalMemory() noexcept = default; + GlobalMemory() noexcept { + } explicit GlobalMemory(HGLOBAL hand_) noexcept : hand(hand_) { if (hand) { ptr = ::GlobalLock(hand); @@ -2906,7 +2512,7 @@ public: HGLOBAL handCopy = hand; ::GlobalUnlock(hand); ptr = nullptr; - hand = nullptr; + hand = {}; return handCopy; } void SetClip(UINT uFormat) noexcept { @@ -2915,7 +2521,7 @@ public: operator bool() const noexcept { return ptr != nullptr; } - SIZE_T Size() noexcept { + SIZE_T Size() const noexcept { return ::GlobalSize(hand); } }; @@ -2924,9 +2530,9 @@ public: // Try up to 8 times, with an initial delay of 1 ms and an exponential back off // for a maximum total delay of 127 ms (1+2+4+8+16+32+64). bool OpenClipboardRetry(HWND hwnd) noexcept { - for (int attempt = 0; attempt < 8; attempt++) { + for (int attempt=0; attempt<8; attempt++) { if (attempt > 0) { - ::Sleep(1 << (attempt - 1)); + ::Sleep(1 << (attempt-1)); } if (::OpenClipboard(hwnd)) { return true; @@ -2935,27 +2541,25 @@ bool OpenClipboardRetry(HWND hwnd) noexcept { return false; } -inline bool IsValidFormatEtc(const FORMATETC *pFE) noexcept { - return pFE->ptd == nullptr - && (pFE->dwAspect & DVASPECT_CONTENT) != 0 - && pFE->lindex == -1 - && (pFE->tymed & TYMED_HGLOBAL) != 0; +bool IsValidFormatEtc(const FORMATETC *pFE) noexcept { + return pFE->ptd == nullptr && + (pFE->dwAspect & DVASPECT_CONTENT) != 0 && + pFE->lindex == -1 && + (pFE->tymed & TYMED_HGLOBAL) != 0; } -inline bool SupportedFormat(const FORMATETC *pFE) noexcept { - return (pFE->cfFormat == CF_UNICODETEXT || pFE->cfFormat == CF_TEXT) - && IsValidFormatEtc(pFE); +bool SupportedFormat(const FORMATETC *pFE) noexcept { + return pFE->cfFormat == CF_UNICODETEXT && + IsValidFormatEtc(pFE); } } -void ScintillaWin::Paste(bool asBinary) { +void ScintillaWin::Paste() { if (!::OpenClipboardRetry(MainHWND())) { return; } - UndoGroup ug(pdoc); - //EnumAllClipboardFormat("Paste"); const bool isLine = SelectionEmpty() && (::IsClipboardFormatAvailable(cfLineSelect) || ::IsClipboardFormatAvailable(cfVSLineTag)); ClearSelection(multiPasteMode == SC_MULTIPASTE_EACH); @@ -2971,15 +2575,6 @@ void ScintillaWin::Paste(bool asBinary) { } const PasteShape pasteShape = isRectangular ? PasteShape::rectangular : (isLine ? PasteShape::line : PasteShape::stream); - if (asBinary) { - // get data with CF_TEXT, decode and verify length information - if (!asBinary) { - ::CloseClipboard(); - Redraw(); - return; - } - } - // Use CF_UNICODETEXT if available GlobalMemory memUSelection(::GetClipboardData(CF_UNICODETEXT)); if (const wchar_t *uptr = static_cast(memUSelection.ptr)) { @@ -2991,20 +2586,21 @@ void ScintillaWin::Paste(bool asBinary) { Redraw(); } -void ScintillaWin::CreateCallTipWindow(PRectangle) noexcept { +void ScintillaWin::CreateCallTipWindow(PRectangle) { if (!ct.wCallTip.Created()) { - HWND wnd = ::CreateWindow(callClassName, L"ACallTip", - WS_POPUP, 100, 100, 150, 20, - MainHWND(), nullptr, - GetWindowInstance(MainHWND()), - this); + HWND wnd = ::CreateWindow(callClassName, TEXT("ACallTip"), + WS_POPUP, 100, 100, 150, 20, + MainHWND(), 0, + GetWindowInstance(MainHWND()), + this); ct.wCallTip = wnd; ct.wDraw = wnd; } } +// >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> #if SCI_EnablePopupMenu -void ScintillaWin::AddToPopUp(const char *label, int cmd, bool enabled) noexcept { +void ScintillaWin::AddToPopUp(const char* label, int cmd, bool enabled) { HMENU hmenuPopup = static_cast(popup.GetID()); if (!label[0]) ::AppendMenuA(hmenuPopup, MF_SEPARATOR, 0, ""); @@ -3014,130 +2610,162 @@ void ScintillaWin::AddToPopUp(const char *label, int cmd, bool enabled) noexcept ::AppendMenuA(hmenuPopup, MF_STRING | MF_DISABLED | MF_GRAYED, cmd, label); } #endif +// <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< -void ScintillaWin::ClaimSelection() noexcept { +void ScintillaWin::ClaimSelection() { // Windows does not have a primary selection } /// Implement IUnknown -STDMETHODIMP FormatEnumerator::QueryInterface(REFIID riid, PVOID *ppv) noexcept { + +STDMETHODIMP_(ULONG)FormatEnumerator_AddRef(FormatEnumerator *fe); +STDMETHODIMP FormatEnumerator_QueryInterface(FormatEnumerator *fe, REFIID riid, PVOID *ppv) { //Platform::DebugPrintf("EFE QI"); *ppv = nullptr; - if (riid == IID_IUnknown || riid == IID_IEnumFORMATETC) { - *ppv = this; - } else { + if (riid == IID_IUnknown) + *ppv = reinterpret_cast(fe); + if (riid == IID_IEnumFORMATETC) + *ppv = reinterpret_cast(fe); + if (!*ppv) return E_NOINTERFACE; - } - AddRef(); + FormatEnumerator_AddRef(fe); return S_OK; } -STDMETHODIMP_(ULONG)FormatEnumerator::AddRef() noexcept { - return ++ref; +STDMETHODIMP_(ULONG)FormatEnumerator_AddRef(FormatEnumerator *fe) { + return ++fe->ref; } -STDMETHODIMP_(ULONG)FormatEnumerator::Release() noexcept { - const ULONG refs = --ref; - if (refs == 0) { - delete this; - } - return refs; +STDMETHODIMP_(ULONG)FormatEnumerator_Release(FormatEnumerator *fe) { + fe->ref--; + if (fe->ref > 0) + return fe->ref; + delete fe; + return 0; } - /// Implement IEnumFORMATETC -STDMETHODIMP FormatEnumerator::Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched) noexcept { +STDMETHODIMP FormatEnumerator_Next(FormatEnumerator *fe, ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched) { if (!rgelt) return E_POINTER; ULONG putPos = 0; - while ((pos < formats.size()) && (putPos < celt)) { - rgelt->cfFormat = formats[pos]; + while ((fe->pos < fe->formats.size()) && (putPos < celt)) { + rgelt->cfFormat = fe->formats[fe->pos]; rgelt->ptd = nullptr; rgelt->dwAspect = DVASPECT_CONTENT; rgelt->lindex = -1; rgelt->tymed = TYMED_HGLOBAL; rgelt++; - pos++; + fe->pos++; putPos++; } if (pceltFetched) *pceltFetched = putPos; return putPos ? S_OK : S_FALSE; } -STDMETHODIMP FormatEnumerator::Skip(ULONG celt) noexcept { - pos += celt; +STDMETHODIMP FormatEnumerator_Skip(FormatEnumerator *fe, ULONG celt) { + fe->pos += celt; return S_OK; } -STDMETHODIMP FormatEnumerator::Reset() noexcept { - pos = 0; +STDMETHODIMP FormatEnumerator_Reset(FormatEnumerator *fe) { + fe->pos = 0; return S_OK; } -STDMETHODIMP FormatEnumerator::Clone(IEnumFORMATETC **ppenum) { +STDMETHODIMP FormatEnumerator_Clone(FormatEnumerator *fe, IEnumFORMATETC **ppenum) { FormatEnumerator *pfe; try { - pfe = new FormatEnumerator(pos, formats.data(), formats.size()); + pfe = new FormatEnumerator(fe->pos, &fe->formats[0], fe->formats.size()); } catch (...) { return E_OUTOFMEMORY; } - return pfe->QueryInterface(IID_IEnumFORMATETC, reinterpret_cast(ppenum)); + return FormatEnumerator_QueryInterface(pfe, IID_IEnumFORMATETC, + reinterpret_cast(ppenum)); } +static VFunction *vtFormatEnumerator[] = { + (VFunction *)(FormatEnumerator_QueryInterface), + (VFunction *)(FormatEnumerator_AddRef), + (VFunction *)(FormatEnumerator_Release), + (VFunction *)(FormatEnumerator_Next), + (VFunction *)(FormatEnumerator_Skip), + (VFunction *)(FormatEnumerator_Reset), + (VFunction *)(FormatEnumerator_Clone) +}; + FormatEnumerator::FormatEnumerator(ULONG pos_, const CLIPFORMAT formats_[], size_t formatsLen_) { + vtbl = vtFormatEnumerator; ref = 0; // First QI adds first reference... pos = pos_; - formats.insert(formats.begin(), formats_, formats_ + formatsLen_); + formats.insert(formats.begin(), formats_, formats_+formatsLen_); } /// Implement IUnknown -STDMETHODIMP DropSource::QueryInterface(REFIID riid, PVOID *ppv) noexcept { - return sci->QueryInterface(riid, ppv); +STDMETHODIMP DropSource_QueryInterface(DropSource *ds, REFIID riid, PVOID *ppv) { + return ds->sci->QueryInterface(riid, ppv); } -STDMETHODIMP_(ULONG)DropSource::AddRef() noexcept { - return sci->AddRef(); +STDMETHODIMP_(ULONG)DropSource_AddRef(DropSource *ds) { + return ds->sci->AddRef(); } -STDMETHODIMP_(ULONG)DropSource::Release() noexcept { - return sci->Release(); +STDMETHODIMP_(ULONG)DropSource_Release(DropSource *ds) { + return ds->sci->Release(); } /// Implement IDropSource -STDMETHODIMP DropSource::QueryContinueDrag(BOOL fEsc, DWORD grfKeyState) noexcept { +STDMETHODIMP DropSource_QueryContinueDrag(DropSource *, BOOL fEsc, DWORD grfKeyState) { if (fEsc) return DRAGDROP_S_CANCEL; if (!(grfKeyState & MK_LBUTTON)) return DRAGDROP_S_DROP; return S_OK; } -STDMETHODIMP DropSource::GiveFeedback(DWORD) noexcept { + +STDMETHODIMP DropSource_GiveFeedback(DropSource *, DWORD) { return DRAGDROP_S_USEDEFAULTCURSORS; } +static VFunction *vtDropSource[] = { + (VFunction *)(DropSource_QueryInterface), + (VFunction *)(DropSource_AddRef), + (VFunction *)(DropSource_Release), + (VFunction *)(DropSource_QueryContinueDrag), + (VFunction *)(DropSource_GiveFeedback) +}; + +DropSource::DropSource() noexcept { + vtbl = vtDropSource; + sci = nullptr; +} + /// Implement IUnkown -STDMETHODIMP DataObject::QueryInterface(REFIID riid, PVOID *ppv) noexcept { - //Platform::DebugPrintf("DO QI %p\n", this); - return sci->QueryInterface(riid, ppv); +STDMETHODIMP DataObject_QueryInterface(DataObject *pd, REFIID riid, PVOID *ppv) { + //Platform::DebugPrintf("DO QI %x\n", pd); + return pd->sci->QueryInterface(riid, ppv); } -STDMETHODIMP_(ULONG)DataObject::AddRef() noexcept { - return sci->AddRef(); +STDMETHODIMP_(ULONG)DataObject_AddRef(DataObject *pd) { + return pd->sci->AddRef(); } -STDMETHODIMP_(ULONG)DataObject::Release() noexcept { - return sci->Release(); +STDMETHODIMP_(ULONG)DataObject_Release(DataObject *pd) { + return pd->sci->Release(); } - /// Implement IDataObject -STDMETHODIMP DataObject::GetData(FORMATETC *pFEIn, STGMEDIUM *pSTM) { - return sci->GetData(pFEIn, pSTM); +STDMETHODIMP DataObject_GetData(DataObject *pd, FORMATETC *pFEIn, STGMEDIUM *pSTM) { + return pd->sci->GetData(pFEIn, pSTM); } -STDMETHODIMP DataObject::GetDataHere(FORMATETC *, STGMEDIUM *) noexcept { +STDMETHODIMP DataObject_GetDataHere(DataObject *, FORMATETC *, STGMEDIUM *) { //Platform::DebugPrintf("DOB GetDataHere\n"); return E_NOTIMPL; } -STDMETHODIMP DataObject::QueryGetData(FORMATETC *pFE) noexcept { - if (sci->DragIsRectangularOK(pFE->cfFormat) && IsValidFormatEtc(pFE)) { +STDMETHODIMP DataObject_QueryGetData(DataObject *pd, FORMATETC *pFE) { + if (pd->sci->DragIsRectangularOK(pFE->cfFormat) && IsValidFormatEtc(pFE)) { return S_OK; } - return SupportedFormat(pFE)? S_OK : S_FALSE; + if (SupportedFormat(pFE)) { + return S_OK; + } else { + return S_FALSE; + } } -STDMETHODIMP DataObject::GetCanonicalFormatEtc(FORMATETC *, FORMATETC *pFEOut) noexcept { +STDMETHODIMP DataObject_GetCanonicalFormatEtc(DataObject *, FORMATETC *, FORMATETC *pFEOut) { //Platform::DebugPrintf("DOB GetCanon\n"); pFEOut->cfFormat = CF_UNICODETEXT; pFEOut->ptd = nullptr; @@ -3147,70 +2775,128 @@ STDMETHODIMP DataObject::GetCanonicalFormatEtc(FORMATETC *, FORMATETC *pFEOut) n return S_OK; } -STDMETHODIMP DataObject::SetData(FORMATETC *, STGMEDIUM *, BOOL) noexcept { +STDMETHODIMP DataObject_SetData(DataObject *, FORMATETC *, STGMEDIUM *, BOOL) { //Platform::DebugPrintf("DOB SetData\n"); return E_FAIL; } -STDMETHODIMP DataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnum) { +STDMETHODIMP DataObject_EnumFormatEtc(DataObject *pd, DWORD dwDirection, IEnumFORMATETC **ppEnum) { try { - //Platform::DebugPrintf("DOB EnumFormatEtc %lu\n", dwDirection); + //Platform::DebugPrintf("DOB EnumFormatEtc %d\n", dwDirection); if (dwDirection != DATADIR_GET) { *ppEnum = nullptr; return E_FAIL; } - const CLIPFORMAT formats[] = { CF_UNICODETEXT, CF_TEXT }; + const CLIPFORMAT formats[] = {CF_UNICODETEXT}; FormatEnumerator *pfe = new FormatEnumerator(0, formats, std::size(formats)); - return pfe->QueryInterface(IID_IEnumFORMATETC, reinterpret_cast(ppEnum)); + return FormatEnumerator_QueryInterface(pfe, IID_IEnumFORMATETC, + reinterpret_cast(ppEnum)); } catch (std::bad_alloc &) { - sci->errorStatus = SC_STATUS_BADALLOC; + pd->sci->errorStatus = SC_STATUS_BADALLOC; return E_OUTOFMEMORY; } catch (...) { - sci->errorStatus = SC_STATUS_FAILURE; + pd->sci->errorStatus = SC_STATUS_FAILURE; return E_FAIL; } } -STDMETHODIMP DataObject::DAdvise(FORMATETC *, DWORD, IAdviseSink *, PDWORD) noexcept { +STDMETHODIMP DataObject_DAdvise(DataObject *, FORMATETC *, DWORD, IAdviseSink *, PDWORD) { //Platform::DebugPrintf("DOB DAdvise\n"); return E_FAIL; } -STDMETHODIMP DataObject::DUnadvise(DWORD) noexcept { +STDMETHODIMP DataObject_DUnadvise(DataObject *, DWORD) { //Platform::DebugPrintf("DOB DUnadvise\n"); return E_FAIL; } -STDMETHODIMP DataObject::EnumDAdvise(IEnumSTATDATA **) noexcept { +STDMETHODIMP DataObject_EnumDAdvise(DataObject *, IEnumSTATDATA **) { //Platform::DebugPrintf("DOB EnumDAdvise\n"); return E_FAIL; } +static VFunction *vtDataObject[] = { + (VFunction *)(DataObject_QueryInterface), + (VFunction *)(DataObject_AddRef), + (VFunction *)(DataObject_Release), + (VFunction *)(DataObject_GetData), + (VFunction *)(DataObject_GetDataHere), + (VFunction *)(DataObject_QueryGetData), + (VFunction *)(DataObject_GetCanonicalFormatEtc), + (VFunction *)(DataObject_SetData), + (VFunction *)(DataObject_EnumFormatEtc), + (VFunction *)(DataObject_DAdvise), + (VFunction *)(DataObject_DUnadvise), + (VFunction *)(DataObject_EnumDAdvise) +}; + +DataObject::DataObject() noexcept { + vtbl = vtDataObject; + sci = nullptr; +} + /// Implement IUnknown -STDMETHODIMP DropTarget::QueryInterface(REFIID riid, PVOID *ppv) noexcept { - //Platform::DebugPrintf("DT QI %p\n", this); - return sci->QueryInterface(riid, ppv); +STDMETHODIMP DropTarget_QueryInterface(DropTarget *dt, REFIID riid, PVOID *ppv) { + //Platform::DebugPrintf("DT QI %x\n", dt); + return dt->sci->QueryInterface(riid, ppv); } -STDMETHODIMP_(ULONG)DropTarget::AddRef() noexcept { - return sci->AddRef(); +STDMETHODIMP_(ULONG)DropTarget_AddRef(DropTarget *dt) { + return dt->sci->AddRef(); } -STDMETHODIMP_(ULONG)DropTarget::Release() noexcept { - return sci->Release(); +STDMETHODIMP_(ULONG)DropTarget_Release(DropTarget *dt) { + return dt->sci->Release(); } /// Implement IDropTarget by forwarding to Scintilla -STDMETHODIMP DropTarget::DragEnter(LPDATAOBJECT pIDataSource, DWORD grfKeyState, POINTL pt, PDWORD pdwEffect) { - return sci->DragEnter(pIDataSource, grfKeyState, pt, pdwEffect); +STDMETHODIMP DropTarget_DragEnter(DropTarget *dt, LPDATAOBJECT pIDataSource, DWORD grfKeyState, + POINTL pt, PDWORD pdwEffect) { + try { + return dt->sci->DragEnter(pIDataSource, grfKeyState, pt, pdwEffect); + } catch (...) { + dt->sci->errorStatus = SC_STATUS_FAILURE; + } + return E_FAIL; } -STDMETHODIMP DropTarget::DragOver(DWORD grfKeyState, POINTL pt, PDWORD pdwEffect) { - return sci->DragOver(grfKeyState, pt, pdwEffect); +STDMETHODIMP DropTarget_DragOver(DropTarget *dt, DWORD grfKeyState, POINTL pt, PDWORD pdwEffect) { + try { + return dt->sci->DragOver(grfKeyState, pt, pdwEffect); + } catch (...) { + dt->sci->errorStatus = SC_STATUS_FAILURE; + } + return E_FAIL; } -STDMETHODIMP DropTarget::DragLeave() { - return sci->DragLeave(); +STDMETHODIMP DropTarget_DragLeave(DropTarget *dt) { + try { + return dt->sci->DragLeave(); + } catch (...) { + dt->sci->errorStatus = SC_STATUS_FAILURE; + } + return E_FAIL; } -STDMETHODIMP DropTarget::Drop(LPDATAOBJECT pIDataSource, DWORD grfKeyState, POINTL pt, PDWORD pdwEffect) { - return sci->Drop(pIDataSource, grfKeyState, pt, pdwEffect); +STDMETHODIMP DropTarget_Drop(DropTarget *dt, LPDATAOBJECT pIDataSource, DWORD grfKeyState, + POINTL pt, PDWORD pdwEffect) { + try { + return dt->sci->Drop(pIDataSource, grfKeyState, pt, pdwEffect); + } catch (...) { + dt->sci->errorStatus = SC_STATUS_FAILURE; + } + return E_FAIL; +} + +static VFunction *vtDropTarget[] = { + (VFunction *)(DropTarget_QueryInterface), + (VFunction *)(DropTarget_AddRef), + (VFunction *)(DropTarget_Release), + (VFunction *)(DropTarget_DragEnter), + (VFunction *)(DropTarget_DragOver), + (VFunction *)(DropTarget_DragLeave), + (VFunction *)(DropTarget_Drop) +}; + +DropTarget::DropTarget() noexcept { + vtbl = vtDropTarget; + sci = nullptr; } /** @@ -3233,13 +2919,14 @@ void ScintillaWin::ImeStartComposition() { // Since the style creation code has been made platform independent, // The logfont for the IME is recreated here. const int styleHere = pdoc->StyleIndexAt(sel.MainCaret()); - LOGFONTW lf {}; - const int sizeZoomed = GetFontSizeZoomed(vs.styles[styleHere].size, vs.zoomLevel); + LOGFONTW lf = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L""}; + int sizeZoomed = vs.styles[styleHere].size + vs.zoomLevel * SC_FONT_SIZE_MULTIPLIER; + if (sizeZoomed <= 2 * SC_FONT_SIZE_MULTIPLIER) // Hangs if sizeZoomed <= 1 + sizeZoomed = 2 * SC_FONT_SIZE_MULTIPLIER; // The negative is to allow for leading - lf.lfHeight = -::MulDiv(sizeZoomed, dpi.y, 72 * SC_FONT_SIZE_MULTIPLIER); - lf.lfWidth = 0; // vs.styles[styleHere].stretch ? + lf.lfHeight = -::MulDiv(sizeZoomed, dpi, 72*SC_FONT_SIZE_MULTIPLIER); lf.lfWeight = vs.styles[styleHere].weight; - lf.lfItalic = vs.styles[styleHere].italic ? TRUE : FALSE; + lf.lfItalic = vs.styles[styleHere].italic ? 1 : 0; lf.lfCharSet = DEFAULT_CHARSET; lf.lfFaceName[0] = L'\0'; if (vs.styles[styleHere].fontName) { @@ -3254,9 +2941,7 @@ void ScintillaWin::ImeStartComposition() { } } -/** Called when IME Window closed. -* TODO: see Chromium's InputMethodWinImm32::OnImeEndComposition(). -*/ +/** Called when IME Window closed. */ void ScintillaWin::ImeEndComposition() { // clear IME composition state. view.imeCaretBlockOverride = false; @@ -3277,17 +2962,17 @@ LRESULT ScintillaWin::ImeOnReconvert(LPARAM lParam) { if ((baseStart == baseEnd) || (mainEnd > baseEnd)) return 0; - const UINT codePage = CodePageOfDocument(); + const int codePage = CodePageOfDocument(); const std::wstring rcFeed = StringDecode(RangeText(baseStart, baseEnd), codePage); - const DWORD rcFeedLen = static_cast(rcFeed.length()) * sizeof(wchar_t); - const DWORD rcSize = sizeof(RECONVERTSTRING) + rcFeedLen + sizeof(wchar_t); + const int rcFeedLen = static_cast(rcFeed.length()) * sizeof(wchar_t); + const int rcSize = sizeof(RECONVERTSTRING) + rcFeedLen + sizeof(wchar_t); RECONVERTSTRING *rc = static_cast(PtrFromSPtr(lParam)); if (!rc) return rcSize; // Immediately be back with rcSize of memory block. wchar_t *rcFeedStart = reinterpret_cast(rc + 1); - memcpy(rcFeedStart, rcFeed.data(), rcFeedLen); + memcpy(rcFeedStart, &rcFeed[0], rcFeedLen); std::string rcCompString = RangeText(mainStart, mainEnd); std::wstring rcCompWstring = StringDecode(rcCompString, codePage); @@ -3302,7 +2987,7 @@ LRESULT ScintillaWin::ImeOnReconvert(LPARAM lParam) { rc->dwCompStrLen = static_cast(rcCompWstring.length()); rc->dwCompStrOffset = static_cast(rcCompWstart.length()) * sizeof(wchar_t); rc->dwTargetStrLen = rc->dwCompStrLen; - rc->dwTargetStrOffset = rc->dwCompStrOffset; + rc->dwTargetStrOffset =rc->dwCompStrOffset; IMContext imc(MainHWND()); if (!imc.hIMC) @@ -3312,18 +2997,18 @@ LRESULT ScintillaWin::ImeOnReconvert(LPARAM lParam) { return 0; // No selection asks IME to fill target fields with its own value. - const DWORD tgWlen = rc->dwTargetStrLen; - const DWORD tgWstart = rc->dwTargetStrOffset / sizeof(wchar_t); + const int tgWlen = rc->dwTargetStrLen; + const int tgWstart = rc->dwTargetStrOffset / sizeof(wchar_t); std::string tgCompStart = StringEncode(rcFeed.substr(0, tgWstart), codePage); std::string tgComp = StringEncode(rcFeed.substr(tgWstart, tgWlen), codePage); // No selection needs to adjust reconvert start position for IME set. - const Sci::Position adjust = tgCompStart.length() - rcCompStart.length(); - const Sci::Position docCompLen = tgComp.length(); + const int adjust = static_cast(tgCompStart.length() - rcCompStart.length()); + const int docCompLen = static_cast(tgComp.length()); // Make place for next composition string to sit in. - for (size_t r = 0; r < sel.Count(); r++) { + for (size_t r=0; r(gmUnicode.ptr), uchars); - } - } else { - // Not Unicode mode - // Convert to Unicode using the current Scintilla code page - const UINT cpSrc = CodePageFromCharSet(selectedText.characterSet, selectedText.codePage); - const size_t uLen = WideCharLenFromMultiByte(cpSrc, svSelected); - gmUnicode.Allocate(2 * uLen); - if (gmUnicode) { - WideCharFromMultiByte(cpSrc, svSelected, static_cast(gmUnicode.ptr), uLen); - } - } - break; - - case CopyEncoding::Ansi: { - std::string s; - if (IsUnicodeMode()) { - const std::wstring wsv = StringDecode(svSelected, CP_UTF8); - s = StringEncode(wsv, CP_ACP); - } else { - // no need to convert selectedText to CP_ACP - s = svSelected; - } - gmUnicode.Allocate(s.size() + 1); + if (IsUnicodeMode()) { + const size_t uchars = UTF16Length(svSelected); + gmUnicode.Allocate(2 * uchars); if (gmUnicode) { - memcpy(gmUnicode.ptr, s.c_str(), s.size()); + UTF16FromUTF8(svSelected, + static_cast(gmUnicode.ptr), uchars); } - } - break; - - case CopyEncoding::Binary: - gmUnicode.Allocate(svSelected.size()); + } else { + // Not Unicode mode + // Convert to Unicode using the current Scintilla code page + const UINT cpSrc = CodePageFromCharSet( + selectedText.characterSet, selectedText.codePage); + const size_t uLen = WideCharLenFromMultiByte(cpSrc, svSelected); + gmUnicode.Allocate(2 * uLen); if (gmUnicode) { - memcpy(gmUnicode.ptr, svSelected.data(), svSelected.size() - 1); + WideCharFromMultiByte(cpSrc, svSelected, + static_cast(gmUnicode.ptr), uLen); } - break; } } @@ -3406,18 +3066,13 @@ void ScintillaWin::CopyToClipboard(const SelectionText &selectedText) { ::EmptyClipboard(); GlobalMemory uniText; - CopyToGlobal(uniText, selectedText, selectedText.asBinary ? CopyEncoding::Binary : CopyEncoding::Unicode); - + CopyToGlobal(uniText, selectedText); if (uniText) { - uniText.SetClip(selectedText.asBinary ? CF_TEXT : CF_UNICODETEXT); - - if (selectedText.asBinary) { - // encode length information - } + uniText.SetClip(CF_UNICODETEXT); } if (selectedText.rectangular) { - ::SetClipboardData(cfColumnSelect, nullptr); + ::SetClipboardData(cfColumnSelect, 0); GlobalMemory borlandSelection; borlandSelection.Allocate(1); @@ -3428,19 +3083,15 @@ void ScintillaWin::CopyToClipboard(const SelectionText &selectedText) { } if (selectedText.lineCopy) { - ::SetClipboardData(cfLineSelect, nullptr); - ::SetClipboardData(cfVSLineTag, nullptr); + ::SetClipboardData(cfLineSelect, 0); + ::SetClipboardData(cfVSLineTag, 0); } ::CloseClipboard(); - - // TODO: notify data loss - //if (!selectedText.asBinary && ) { - //} } void ScintillaWin::ScrollMessage(WPARAM wParam) { - //DWORD dwStart = GetTickCount(); + //DWORD dwStart = timeGetTime(); //Platform::DebugPrintf("Scroll %x %d\n", wParam, lParam); SCROLLINFO sci = {}; @@ -3449,7 +3100,7 @@ void ScintillaWin::ScrollMessage(WPARAM wParam) { GetScrollInfo(SB_VERT, &sci); - //Platform::DebugPrintf("ScrollInfo %d mask=%x min=%d max=%d page=%d pos=%d track=%d\n", b, sci.fMask, + //Platform::DebugPrintf("ScrollInfo %d mask=%x min=%d max=%d page=%d pos=%d track=%d\n", b,sci.fMask, //sci.nMin, sci.nMax, sci.nPage, sci.nPos, sci.nTrackPos); Sci::Line topLineNew = topLine; switch (LOWORD(wParam)) { @@ -3498,15 +3149,15 @@ void ScintillaWin::HorizontalScrollMessage(WPARAM wParam) { break; case SB_THUMBPOSITION: case SB_THUMBTRACK: { - // Do NOT use wParam, its 16 bit and not enough for very long lines. Its still possible to overflow the 32 bit but you have to try harder =] - SCROLLINFO si; - si.cbSize = sizeof(si); - si.fMask = SIF_TRACKPOS; - if (GetScrollInfo(SB_HORZ, &si)) { - xPos = si.nTrackPos; + // Do NOT use wParam, its 16 bit and not enough for very long lines. Its still possible to overflow the 32 bit but you have to try harder =] + SCROLLINFO si; + si.cbSize = sizeof(si); + si.fMask = SIF_TRACKPOS; + if (GetScrollInfo(SB_HORZ, &si)) { + xPos = si.nTrackPos; + } } - } - break; + break; } HorizontalScrollTo(xPos); } @@ -3539,13 +3190,13 @@ void ScintillaWin::FullPaintDC(HDC hdc) { namespace { -inline bool CompareDevCap(HDC hdc, HDC hOtherDC, int nIndex) noexcept { +bool CompareDevCap(HDC hdc, HDC hOtherDC, int nIndex) noexcept { return ::GetDeviceCaps(hdc, nIndex) == ::GetDeviceCaps(hOtherDC, nIndex); } } -bool ScintillaWin::IsCompatibleDC(HDC hOtherDC) const noexcept { +bool ScintillaWin::IsCompatibleDC(HDC hOtherDC) noexcept { HDC hdc = ::GetDC(MainHWND()); const bool isCompatible = CompareDevCap(hdc, hOtherDC, TECHNOLOGY) && @@ -3557,165 +3208,58 @@ bool ScintillaWin::IsCompatibleDC(HDC hOtherDC) const noexcept { return isCompatible; } -// https://docs.microsoft.com/en-us/windows/desktop/api/oleidl/nf-oleidl-idroptarget-dragenter DWORD ScintillaWin::EffectFromState(DWORD grfKeyState) const noexcept { // These are the Wordpad semantics. - // DROPEFFECT_COPY not works for some applications like Github Atom. - DWORD dwEffect = DROPEFFECT_MOVE; -#if 0 + DWORD dwEffect; if (inDragDrop == DragDrop::dragging) // Internal defaults to move dwEffect = DROPEFFECT_MOVE; else dwEffect = DROPEFFECT_COPY; - if ((grfKeyState & MK_CONTROL) && (grfKeyState & MK_SHIFT)) - dwEffect = DROPEFFECT_LINK; - else - if (grfKeyState & (MK_ALT | MK_SHIFT)) + if (grfKeyState & MK_ALT) dwEffect = DROPEFFECT_MOVE; - else -#endif if (grfKeyState & MK_CONTROL) dwEffect = DROPEFFECT_COPY; return dwEffect; } /// Implement IUnknown -STDMETHODIMP ScintillaWin::QueryInterface(REFIID riid, PVOID *ppv) noexcept { +STDMETHODIMP ScintillaWin::QueryInterface(REFIID riid, PVOID *ppv) { *ppv = nullptr; - if (riid == IID_IUnknown) { - *ppv = &dt; - } else if (riid == IID_IDropSource) { - *ppv = &ds; - } else if (riid == IID_IDropTarget) { - *ppv = &dt; - } else if (riid == IID_IDataObject) { - *ppv = &dob; - } - if (!*ppv) { + if (riid == IID_IUnknown) + *ppv = reinterpret_cast(&dt); + if (riid == IID_IDropSource) + *ppv = reinterpret_cast(&ds); + if (riid == IID_IDropTarget) + *ppv = reinterpret_cast(&dt); + if (riid == IID_IDataObject) + *ppv = reinterpret_cast(&dob); + if (!*ppv) return E_NOINTERFACE; - } return S_OK; } -STDMETHODIMP_(ULONG) ScintillaWin::AddRef() noexcept { +STDMETHODIMP_(ULONG) ScintillaWin::AddRef() { return 1; } -STDMETHODIMP_(ULONG) ScintillaWin::Release() noexcept { +STDMETHODIMP_(ULONG) ScintillaWin::Release() { return 1; } -#if DebugDragAndDropDataFormat - -namespace { - -const char* GetStorageMediumType(DWORD tymed) noexcept { - switch (tymed) { - case TYMED_HGLOBAL: - return "TYMED_HGLOBAL"; - case TYMED_FILE: - return "TYMED_FILE"; - case TYMED_ISTREAM: - return "TYMED_ISTREAM"; - case TYMED_ISTORAGE: - return "TYMED_ISTORAGE"; - default: - return "Unknown"; - } -} - -const char* GetSourceFormatName(UINT fmt, char name[], int cchName) noexcept { - const int len = GetClipboardFormatNameA(fmt, name, cchName); - if (len <= 0) { - switch (fmt) { - case CF_TEXT: - return "CF_TEXT"; - case CF_UNICODETEXT: - return "CF_UNICODETEXT"; - case CF_HDROP: - return "CF_HDROP"; - case CF_LOCALE: - return "CF_LOCALE"; - case CF_OEMTEXT: - return "CF_OEMTEXT"; - default: - return "Unknown"; - } - } - - return name; -} - -} - -// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-idataobject-enumformatetc -void ScintillaWin::EnumDataSourceFormat(const char *tag, LPDATAOBJECT pIDataSource) { - IEnumFORMATETC *fmtEnum = nullptr; - HRESULT hr = pIDataSource->EnumFormatEtc(DATADIR_GET, &fmtEnum); - if (hr == S_OK && fmtEnum) { - FORMATETC fetc[32] = {}; - ULONG fetched = 0; - hr = fmtEnum->Next(sizeof(fetc) / sizeof(fetc[0]), fetc, &fetched); - if (fetched > 0) { - char name[1024]; - char buf[2048]; - for (ULONG i = 0; i < fetched; i++) { - const CLIPFORMAT fmt = fetc[i].cfFormat; - const DWORD tymed = fetc[i].tymed; - const char *typeName = GetStorageMediumType(tymed); - const char *fmtName = GetSourceFormatName(fmt, name, sizeof(name)); - const int len = sprintf(buf, "%s: fmt[%lu]=%u, 0x%04X; tymed=%lu, %s; name=%s\n", - tag, i, fmt, fmt, tymed, typeName, fmtName); - InsertCharacter(std::string_view(buf, len), CharacterSource::tentativeInput); - } - } - } - if (fmtEnum) { - fmtEnum->Release(); - } -} - -// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-enumclipboardformats -void ScintillaWin::EnumAllClipboardFormat(const char *tag) { - UINT fmt = 0; - unsigned int i = 0; - char name[1024]; - char buf[2048]; - while ((fmt = ::EnumClipboardFormats(fmt)) != 0) { - const char *fmtName = GetSourceFormatName(fmt, name, sizeof(name)); - const int len = sprintf(buf, "%s: fmt[%u]=%u, 0x%04X; name=%s\n", - tag, i, fmt, fmt, fmtName); - InsertCharacter(std::string_view(buf, len), CharacterSource::tentativeInput); - i++; - } -} - -#endif - /// Implement IDropTarget -STDMETHODIMP ScintillaWin::DragEnter(LPDATAOBJECT pIDataSource, DWORD grfKeyState, POINTL, PDWORD pdwEffect) { - if (!pIDataSource) { +STDMETHODIMP ScintillaWin::DragEnter(LPDATAOBJECT pIDataSource, DWORD grfKeyState, + POINTL, PDWORD pdwEffect) { + if (!pIDataSource ) return E_POINTER; + FORMATETC fmtu = {CF_UNICODETEXT, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + const HRESULT hrHasUText = pIDataSource->QueryGetData(&fmtu); + hasOKText = (hrHasUText == S_OK); + if (hasOKText) { + *pdwEffect = EffectFromState(grfKeyState); + } else { + *pdwEffect = DROPEFFECT_NONE; } - hasOKText = false; - try { - //EnumDataSourceFormat("DragEnter", pIDataSource); - - for (UINT fmtIndex = 0; fmtIndex < dropFormatCount; fmtIndex++) { - const CLIPFORMAT fmt = dropFormat[fmtIndex]; - FORMATETC fmtu = { fmt, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - const HRESULT hrHasUText = pIDataSource->QueryGetData(&fmtu); - hasOKText = (hrHasUText == S_OK); - if (hasOKText) { - break; - } - } - } catch (...) { - errorStatus = SC_STATUS_FAILURE; - } - - *pdwEffect = hasOKText? EffectFromState(grfKeyState) : DROPEFFECT_NONE; return S_OK; } @@ -3729,7 +3273,7 @@ STDMETHODIMP ScintillaWin::DragOver(DWORD grfKeyState, POINTL pt, PDWORD pdwEffe *pdwEffect = EffectFromState(grfKeyState); // Update the cursor. - POINT rpt = { pt.x, pt.y }; + POINT rpt = {pt.x, pt.y}; ::ScreenToClient(MainHWND(), &rpt); SetDragPosition(SPositionFromLocation(PointFromPOINT(rpt), false, false, UserVirtualSpace())); @@ -3750,115 +3294,46 @@ STDMETHODIMP ScintillaWin::DragLeave() { return E_FAIL; } -STDMETHODIMP ScintillaWin::Drop(LPDATAOBJECT pIDataSource, DWORD grfKeyState, POINTL pt, PDWORD pdwEffect) { +STDMETHODIMP ScintillaWin::Drop(LPDATAOBJECT pIDataSource, DWORD grfKeyState, + POINTL pt, PDWORD pdwEffect) { try { *pdwEffect = EffectFromState(grfKeyState); - if (!pIDataSource) { + if (!pIDataSource) return E_POINTER; - } SetDragPosition(SelectionPosition(Sci::invalidPosition)); std::string putf; - bool fileDrop = false; - HRESULT hr = DV_E_FORMATETC; - - //EnumDataSourceFormat("Drop", pIDataSource); - for (UINT fmtIndex = 0; fmtIndex < dropFormatCount; fmtIndex++) { - const CLIPFORMAT fmt = dropFormat[fmtIndex]; - FORMATETC fmtu = { fmt, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - STGMEDIUM medium {}; - hr = pIDataSource->GetData(&fmtu, &medium); - - if (SUCCEEDED(hr) && medium.hGlobal) { - // File Drop - if (fmt == CF_HDROP -#if EnableDrop_VisualStudioProjectItem - || fmt == cfVSStgProjectItem || fmt == cfVSRefProjectItem -#endif - ) { - WCHAR pathDropped[1024]; - HDROP hDrop = static_cast(medium.hGlobal); - if (::DragQueryFileW(hDrop, 0, pathDropped, sizeof(pathDropped)/sizeof(WCHAR)) > 0) { - WCHAR *p = pathDropped; -#if EnableDrop_VisualStudioProjectItem - if (fmt == cfVSStgProjectItem || fmt == cfVSRefProjectItem) { - // {UUID}|Solution\Project.[xx]proj|path - WCHAR *t = StrRChrW(p, nullptr, L'|'); - if (t) { - p = t + 1; - } - } -#endif - putf = StringEncode(p, CP_UTF8); - fileDrop = true; - } - // TODO: This seems not required, MSDN only says it need be called in WM_DROPFILES - ::DragFinish(hDrop); - } -#if Enable_ChromiumWebCustomMIMEDataFormat - else if (fmt == cfChromiumCustomMIME) { - GlobalMemory memUDrop(medium.hGlobal); - if (const wchar_t *uptr = static_cast(memUDrop.ptr)) { - const std::wstring_view wsv(uptr, memUDrop.Size() / 2); - // parse file url: "resource":"file:///path" - const size_t dataLen = UTF8Length(wsv); - } - memUDrop.Unlock(); - } -#endif - // Unicode Text - else if (fmt == CF_UNICODETEXT) { - GlobalMemory memUDrop(medium.hGlobal); - if (const wchar_t *uptr = static_cast(memUDrop.ptr)) { - putf = EncodeWString(uptr); - } - memUDrop.Unlock(); - } - // ANSI Text - else if (fmt == CF_TEXT) { - GlobalMemory memDrop(medium.hGlobal); - if (const char *ptr = static_cast(memDrop.ptr)) { - const std::string_view sv(ptr, strnlen(ptr, memDrop.Size())); - // In Unicode mode, convert text to UTF-8 - if (IsUnicodeMode()) { - const std::wstring wsv = StringDecode(sv, CP_ACP); - putf = StringEncode(wsv, CP_UTF8); - } else { - // no need to convert ptr from CP_ACP to CodePageOfDocument(). - putf = sv; - } - } - memDrop.Unlock(); - } - } - - ::ReleaseStgMedium(&medium); - if (!putf.empty()) { - break; - } - } - + FORMATETC fmtu = {CF_UNICODETEXT, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; + STGMEDIUM medium{}; + const HRESULT hr = pIDataSource->GetData(&fmtu, &medium); if (!SUCCEEDED(hr)) { return hr; } + if (medium.hGlobal) { + GlobalMemory memUDrop(medium.hGlobal); + if (const wchar_t *uptr = static_cast(memUDrop.ptr)) { + putf = EncodeWString(uptr); + } + memUDrop.Unlock(); + } + if (putf.empty()) { return S_OK; } - if (fileDrop) { - NotifyURIDropped(putf.c_str()); - } else { - FORMATETC fmtr = { cfColumnSelect, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - const bool isRectangular = S_OK == pIDataSource->QueryGetData(&fmtr); + FORMATETC fmtr = {cfColumnSelect, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; + const bool isRectangular = S_OK == pIDataSource->QueryGetData(&fmtr); - POINT rpt = { pt.x, pt.y }; - ::ScreenToClient(MainHWND(), &rpt); - const SelectionPosition movePos = SPositionFromLocation(PointFromPOINT(rpt), false, false, UserVirtualSpace()); + POINT rpt = {pt.x, pt.y}; + ::ScreenToClient(MainHWND(), &rpt); + const SelectionPosition movePos = SPositionFromLocation(PointFromPOINT(rpt), false, false, UserVirtualSpace()); - DropAt(movePos, putf.c_str(), putf.size(), *pdwEffect == DROPEFFECT_MOVE, isRectangular); - } + DropAt(movePos, putf.c_str(), putf.size(), *pdwEffect == DROPEFFECT_MOVE, isRectangular); + + // Free data + ::ReleaseStgMedium(&medium); return S_OK; } catch (...) { @@ -3868,7 +3343,7 @@ STDMETHODIMP ScintillaWin::Drop(LPDATAOBJECT pIDataSource, DWORD grfKeyState, PO } /// Implement important part of IDataObject -STDMETHODIMP ScintillaWin::GetData(const FORMATETC *pFEIn, STGMEDIUM *pSTM) { +STDMETHODIMP ScintillaWin::GetData(FORMATETC *pFEIn, STGMEDIUM *pSTM) { if (!SupportedFormat(pFEIn)) { //Platform::DebugPrintf("DOB GetData No %d %x %x fmt=%x\n", lenDrag, pFEIn, pSTM, pFEIn->cfFormat); return DATA_E_FORMATETC; @@ -3878,38 +3353,30 @@ STDMETHODIMP ScintillaWin::GetData(const FORMATETC *pFEIn, STGMEDIUM *pSTM) { //Platform::DebugPrintf("DOB GetData OK %d %x %x\n", lenDrag, pFEIn, pSTM); GlobalMemory uniText; - CopyToGlobal(uniText, drag, (pFEIn->cfFormat == CF_TEXT)? CopyEncoding::Ansi : CopyEncoding::Unicode); - pSTM->hGlobal = uniText ? uniText.Unlock() : nullptr; + CopyToGlobal(uniText, drag); + pSTM->hGlobal = uniText ? uniText.Unlock() : 0; pSTM->pUnkForRelease = nullptr; return S_OK; } -BOOL CALLBACK ScintillaWin::PrepareOnce(PINIT_ONCE initOnce, PVOID parameter, PVOID *lpContext) noexcept -{ -#if USE_WIN32_INIT_ONCE - UNREFERENCED_PARAMETER(initOnce); - UNREFERENCED_PARAMETER(parameter); - UNREFERENCED_PARAMETER(lpContext); -#endif - +void ScintillaWin::Prepare() noexcept { Platform_Initialise(hInstance); - //~CharClassify::InitUnicodeData(); // Register the CallTip class - WNDCLASSEX wndclassc {}; + WNDCLASSEX wndclassc{}; wndclassc.cbSize = sizeof(wndclassc); wndclassc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW; wndclassc.cbWndExtra = sizeof(ScintillaWin *); wndclassc.hInstance = hInstance; wndclassc.lpfnWndProc = ScintillaWin::CTWndProc; - wndclassc.hCursor = ::LoadCursor({}, IDC_ARROW); + wndclassc.hCursor = ::LoadCursor(NULL, IDC_ARROW); wndclassc.lpszClassName = callClassName; callClassAtom = ::RegisterClassEx(&wndclassc); - return TRUE; } bool ScintillaWin::Register(HINSTANCE hInstance_) noexcept { + hInstance = hInstance_; // Register the Scintilla class @@ -3922,8 +3389,8 @@ bool ScintillaWin::Register(HINSTANCE hInstance_) noexcept { wndclass.hInstance = hInstance; wndclass.lpszClassName = L"Scintilla"; scintillaClassAtom = ::RegisterClassExW(&wndclass); - const bool result = 0 != scintillaClassAtom; + return result; } @@ -3946,7 +3413,7 @@ bool ScintillaWin::Unregister() noexcept { bool ScintillaWin::HasCaretSizeChanged() const noexcept { if ( - ((0 != vs.caretWidth) && (sysCaretWidth != vs.caretWidth)) + ( (0 != vs.caretWidth) && (sysCaretWidth != vs.caretWidth) ) || ((0 != vs.lineHeight) && (sysCaretHeight != vs.lineHeight)) ) { return true; @@ -3964,7 +3431,7 @@ BOOL ScintillaWin::CreateSystemCaret() { sysCaretHeight; std::vector bits(bitmapSize); sysCaretBitmap = ::CreateBitmap(sysCaretWidth, sysCaretHeight, 1, - 1, bits.data()); + 1, &bits[0]); const BOOL retval = ::CreateCaret( MainHWND(), sysCaretBitmap, sysCaretWidth, sysCaretHeight); @@ -3985,7 +3452,7 @@ BOOL ScintillaWin::DestroySystemCaret() noexcept { return retval; } -LRESULT CALLBACK ScintillaWin::CTWndProc( +LRESULT PASCAL ScintillaWin::CTWndProc( HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { // Find C++ object associated with window. ScintillaWin *sciThis = static_cast(PointerFromWindow(hWnd)); @@ -4036,7 +3503,6 @@ LRESULT CALLBACK ScintillaWin::CTWndProc( if (!SUCCEEDED(pD2DFactory->CreateHwndRenderTarget(drtp, dhrtp, &pCTRenderTarget))) { surfaceWindow->Release(); ::EndPaint(hWnd, &ps); - ReleaseUnknown(pCTRenderTarget); return 0; } // If above SUCCEEDED, then pCTRenderTarget not nullptr @@ -4071,7 +3537,7 @@ LRESULT CALLBACK ScintillaWin::CTWndProc( sciThis->CallTipClick(); return 0; } else if (iMessage == WM_SETCURSOR) { - ::SetCursor(::LoadCursor({}, IDC_ARROW)); + ::SetCursor(::LoadCursor(NULL, IDC_ARROW)); return 0; } else if (iMessage == WM_NCHITTEST) { return HTCAPTION; @@ -4086,11 +3552,19 @@ LRESULT CALLBACK ScintillaWin::CTWndProc( } sptr_t ScintillaWin::DirectFunction( - sptr_t ptr, UINT iMessage, uptr_t wParam, sptr_t lParam) { + sptr_t ptr, UINT iMessage, uptr_t wParam, sptr_t lParam) { PLATFORM_ASSERT(::GetCurrentThreadId() == ::GetWindowThreadProcessId(reinterpret_cast(ptr)->MainHWND(), nullptr)); return reinterpret_cast(ptr)->WndProc(iMessage, wParam, lParam); } +namespace Scintilla { + +sptr_t DirectFunction( + ScintillaWin *sci, UINT iMessage, uptr_t wParam, sptr_t lParam) { + return sci->WndProc(iMessage, wParam, lParam); +} + +// >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> #ifdef SCINTILLA_DLL namespace Scintilla { sptr_t DirectFunction(ScintillaWin* sci, UINT iMessage, uptr_t wParam, sptr_t lParam) { @@ -4100,12 +3574,14 @@ namespace Scintilla { #else extern "C" sptr_t SCI_METHOD Scintilla_DirectFunction( - ScintillaWin* sci, UINT iMessage, uptr_t wParam, sptr_t lParam) { + ScintillaWin * sci, UINT iMessage, uptr_t wParam, sptr_t lParam) { return sci->WndProc(iMessage, wParam, lParam); } #endif +// <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< +} -LRESULT CALLBACK ScintillaWin::SWndProc( +LRESULT PASCAL ScintillaWin::SWndProc( HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { //Platform::DebugPrintf("S W:%x M:%x WP:%x L:%x\n", hWnd, iMessage, wParam, lParam); @@ -4115,8 +3591,8 @@ LRESULT CALLBACK ScintillaWin::SWndProc( if (sci == nullptr) { try { if (iMessage == WM_CREATE) { - static INIT_ONCE once = INIT_ONCE_STATIC_INIT; - ::InitOnceExecuteOnce(&once, PrepareOnce, nullptr, nullptr); + static std::once_flag once; + std::call_once(once, Prepare); // Create C++ object associated with window sci = new ScintillaWin(hWnd); SetWindowPointer(hWnd, sci); @@ -4128,8 +3604,8 @@ LRESULT CALLBACK ScintillaWin::SWndProc( } else { if (iMessage == WM_NCDESTROY) { try { - //sci->Finalise(); - delete sci; // Finalise() in d'tor + sci->Finalise(); + delete sci; } catch (...) { } SetWindowPointer(hWnd, nullptr); @@ -4140,61 +3616,48 @@ LRESULT CALLBACK ScintillaWin::SWndProc( } } -namespace Scintilla { - // This function is externally visible so it can be called from container when building statically. // Must be called once only. -extern "C" __declspec(dllexport) int Scintilla_RegisterClasses(void *hInstance) { - -#if _WIN32_WINNT < _WIN32_WINNT_WIN8 - // see LoadD2D() in PlatWin.cxx - kSystemLibraryLoadFlags = (IsWindows8Point1OrGreater() || GetProcAddress(GetModuleHandle(L"kernel32.dll"), "SetDefaultDllDirectories")) ? LOAD_LIBRARY_SEARCH_SYSTEM32 : 0; -#endif - - Platform_Initialise(hInstance); - const bool result = ScintillaWin::Register(static_cast(hInstance)); - //@@@CharClassify::InitUnicodeData(); - return result; } - int ResourcesRelease(bool fromDllMain) noexcept { - const bool result = ScintillaWin::Unregister(); - Platform_Finalise(fromDllMain); - return result; - } +namespace Scintilla { +int ResourcesRelease(bool fromDllMain) noexcept { + const bool result = ScintillaWin::Unregister(); + Platform_Finalise(fromDllMain); + return result; +} + +} // This function is externally visible so it can be called from container when building statically. -extern "C" __declspec(dllexport) -int Scintilla_ReleaseResources(void) { +int Scintilla_ReleaseResources() { return Scintilla::ResourcesRelease(false); } +// >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> + extern "C" __declspec(dllexport) int Scintilla_InputCodePage(void) { return InputCodePage(); } extern "C" __declspec(dllexport) -DPI_T Scintilla_GetWindowDPI(void* hwnd) { - return GetWindowDPI(static_cast(hwnd)); +unsigned Scintilla_GetWindowDPI(void* hwnd) { + return Scintilla::DpiForWindow(static_cast(hwnd)); } extern "C" __declspec(dllexport) -int Scintilla_GetSystemMetricsForDpi(int nIndex, DPI_T dpi) { - return SystemMetricsForDpi(nIndex, dpi.y); +int Scintilla_GetSystemMetricsForDpi(int nIndex, unsigned dpi) { + return Scintilla::SystemMetricsForDpi(nIndex, dpi); } extern "C" __declspec(dllexport) -int Scintilla_AdjustWindowRectForDpi(WRCT_T* lpRect, unsigned long dwStyle, unsigned long dwExStyle, DPI_T dpi) { - RECT rc; - rc.left = lpRect->left; rc.top = lpRect->top; rc.right = lpRect->right; rc.bottom = lpRect->bottom; - BOOL const res = AdjustWindowRectForDpi(&rc, dwStyle, dwExStyle, dpi.y); - lpRect->left = rc.left; lpRect->top = rc.top; lpRect->right = rc.right; lpRect->bottom = rc.bottom; - return (int)res; +int Scintilla_AdjustWindowRectForDpi(LPWRECT lpRect, unsigned long dwStyle, unsigned long dwExStyle, unsigned dpi) { + return Scintilla::AdjustWindowRectForDpi(reinterpret_cast(lpRect), dwStyle, dwExStyle, dpi); } -} // namespace Scintilla +// <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< diff --git a/scintilla/win32/deps.mak b/scintilla/win32/deps.mak index c7f7c748c..3fd1b4765 100644 --- a/scintilla/win32/deps.mak +++ b/scintilla/win32/deps.mak @@ -5,7 +5,11 @@ HanjaDic.o: \ HanjaDic.h PlatWin.o: \ PlatWin.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ + ../include/Scintilla.h \ + ../include/Sci_Position.h \ ../src/XPM.h \ ../src/UniConversion.h \ ../src/DBCS.h \ @@ -18,7 +22,9 @@ ScintillaDLL.o: \ ScintillaWin.h ScintillaWin.o: \ ScintillaWin.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ @@ -57,7 +63,9 @@ ScintillaWin.o: \ ScintillaWin.h AutoComplete.o: \ ../src/AutoComplete.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/CharacterSet.h \ @@ -65,11 +73,12 @@ AutoComplete.o: \ ../src/AutoComplete.h CallTip.o: \ ../src/CallTip.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/Position.h \ - ../src/IntegerRectangle.h \ ../src/CallTip.h CaseConvert.o: \ ../src/CaseConvert.cxx \ @@ -81,7 +90,7 @@ CaseFolder.o: \ ../src/CaseConvert.h CellBuffer.o: \ ../src/CellBuffer.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/Position.h \ @@ -101,7 +110,7 @@ CharClassify.o: \ ../src/CharClassify.h ContractionState.o: \ ../src/ContractionState.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ ../src/Position.h \ ../src/UniqueString.h \ ../src/SplitVector.h \ @@ -114,7 +123,7 @@ DBCS.o: \ ../src/DBCS.h Decoration.o: \ ../src/Decoration.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/Position.h \ @@ -124,7 +133,7 @@ Decoration.o: \ ../src/Decoration.h Document.o: \ ../src/Document.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ @@ -146,7 +155,9 @@ Document.o: \ ../src/ElapsedPeriod.h EditModel.o: \ ../src/EditModel.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ @@ -174,7 +185,9 @@ EditModel.o: \ ../src/EditModel.h Editor.o: \ ../src/Editor.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ @@ -208,7 +221,9 @@ Editor.o: \ ../src/ElapsedPeriod.h EditView.o: \ ../src/EditView.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ @@ -216,7 +231,6 @@ EditView.o: \ ../src/CharacterSet.h \ ../src/CharacterCategory.h \ ../src/Position.h \ - ../src/IntegerRectangle.h \ ../src/UniqueString.h \ ../src/SplitVector.h \ ../src/Partitioning.h \ @@ -240,38 +254,45 @@ EditView.o: \ ../src/MarginView.h \ ../src/EditView.h \ ../src/ElapsedPeriod.h +Geometry.o: \ + ../src/Geometry.cxx \ + ../src/Geometry.h Indicator.o: \ ../src/Indicator.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ - ../src/IntegerRectangle.h \ ../src/Indicator.h \ ../src/XPM.h KeyMap.o: \ ../src/KeyMap.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/KeyMap.h LineMarker.o: \ ../src/LineMarker.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ - ../src/IntegerRectangle.h \ ../src/XPM.h \ - ../src/LineMarker.h + ../src/LineMarker.h \ + ../src/UniConversion.h MarginView.o: \ ../src/MarginView.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ ../include/Scintilla.h \ ../src/CharacterCategory.h \ ../src/Position.h \ - ../src/IntegerRectangle.h \ ../src/UniqueString.h \ ../src/SplitVector.h \ ../src/Partitioning.h \ @@ -295,7 +316,9 @@ MarginView.o: \ ../src/EditView.h PerLine.o: \ ../src/PerLine.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/Position.h \ @@ -305,7 +328,9 @@ PerLine.o: \ ../src/PerLine.h PositionCache.o: \ ../src/PositionCache.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ @@ -337,7 +362,7 @@ RESearch.o: \ ../src/RESearch.h RunStyles.o: \ ../src/RunStyles.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/Position.h \ @@ -346,7 +371,9 @@ RunStyles.o: \ ../src/RunStyles.h ScintillaBase.o: \ ../src/ScintillaBase.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ @@ -379,7 +406,9 @@ ScintillaBase.o: \ ../src/ScintillaBase.h ScintillaBaseL.o: \ ../src/ScintillaBase.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ @@ -412,14 +441,16 @@ ScintillaBaseL.o: \ ../src/ScintillaBase.h Selection.o: \ ../src/Selection.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/Position.h \ ../src/Selection.h Style.o: \ ../src/Style.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/Style.h @@ -431,7 +462,9 @@ UniqueString.o: \ ../src/UniqueString.h ViewStyle.o: \ ../src/ViewStyle.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/Position.h \ @@ -443,5 +476,7 @@ ViewStyle.o: \ ../src/ViewStyle.h XPM.o: \ ../src/XPM.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../src/XPM.h diff --git a/scintilla/win32/makefile b/scintilla/win32/makefile index 5e005fe24..7dd2604bb 100644 --- a/scintilla/win32/makefile +++ b/scintilla/win32/makefile @@ -96,6 +96,7 @@ SRC_OBJS = \ EditModel.o \ Editor.o \ EditView.o \ + Geometry.o \ Indicator.o \ KeyMap.o \ LineMarker.o \ diff --git a/scintilla/win32/nmdeps.mak b/scintilla/win32/nmdeps.mak index 0f7ab1f33..b831d6add 100644 --- a/scintilla/win32/nmdeps.mak +++ b/scintilla/win32/nmdeps.mak @@ -5,7 +5,11 @@ $(DIR_O)/HanjaDic.obj: \ HanjaDic.h $(DIR_O)/PlatWin.obj: \ PlatWin.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ + ../include/Scintilla.h \ + ../include/Sci_Position.h \ ../src/XPM.h \ ../src/UniConversion.h \ ../src/DBCS.h \ @@ -18,7 +22,9 @@ $(DIR_O)/ScintillaDLL.obj: \ ScintillaWin.h $(DIR_O)/ScintillaWin.obj: \ ScintillaWin.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ @@ -57,7 +63,9 @@ $(DIR_O)/ScintillaWin.obj: \ ScintillaWin.h $(DIR_O)/AutoComplete.obj: \ ../src/AutoComplete.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/CharacterSet.h \ @@ -65,11 +73,12 @@ $(DIR_O)/AutoComplete.obj: \ ../src/AutoComplete.h $(DIR_O)/CallTip.obj: \ ../src/CallTip.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/Position.h \ - ../src/IntegerRectangle.h \ ../src/CallTip.h $(DIR_O)/CaseConvert.obj: \ ../src/CaseConvert.cxx \ @@ -81,7 +90,7 @@ $(DIR_O)/CaseFolder.obj: \ ../src/CaseConvert.h $(DIR_O)/CellBuffer.obj: \ ../src/CellBuffer.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/Position.h \ @@ -101,7 +110,7 @@ $(DIR_O)/CharClassify.obj: \ ../src/CharClassify.h $(DIR_O)/ContractionState.obj: \ ../src/ContractionState.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ ../src/Position.h \ ../src/UniqueString.h \ ../src/SplitVector.h \ @@ -114,7 +123,7 @@ $(DIR_O)/DBCS.obj: \ ../src/DBCS.h $(DIR_O)/Decoration.obj: \ ../src/Decoration.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/Position.h \ @@ -124,7 +133,7 @@ $(DIR_O)/Decoration.obj: \ ../src/Decoration.h $(DIR_O)/Document.obj: \ ../src/Document.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ @@ -146,7 +155,9 @@ $(DIR_O)/Document.obj: \ ../src/ElapsedPeriod.h $(DIR_O)/EditModel.obj: \ ../src/EditModel.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ @@ -174,7 +185,9 @@ $(DIR_O)/EditModel.obj: \ ../src/EditModel.h $(DIR_O)/Editor.obj: \ ../src/Editor.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ @@ -208,7 +221,9 @@ $(DIR_O)/Editor.obj: \ ../src/ElapsedPeriod.h $(DIR_O)/EditView.obj: \ ../src/EditView.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ @@ -216,7 +231,6 @@ $(DIR_O)/EditView.obj: \ ../src/CharacterSet.h \ ../src/CharacterCategory.h \ ../src/Position.h \ - ../src/IntegerRectangle.h \ ../src/UniqueString.h \ ../src/SplitVector.h \ ../src/Partitioning.h \ @@ -240,38 +254,45 @@ $(DIR_O)/EditView.obj: \ ../src/MarginView.h \ ../src/EditView.h \ ../src/ElapsedPeriod.h +$(DIR_O)/Geometry.obj: \ + ../src/Geometry.cxx \ + ../src/Geometry.h $(DIR_O)/Indicator.obj: \ ../src/Indicator.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ - ../src/IntegerRectangle.h \ ../src/Indicator.h \ ../src/XPM.h $(DIR_O)/KeyMap.obj: \ ../src/KeyMap.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/KeyMap.h $(DIR_O)/LineMarker.obj: \ ../src/LineMarker.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ - ../src/IntegerRectangle.h \ ../src/XPM.h \ - ../src/LineMarker.h + ../src/LineMarker.h \ + ../src/UniConversion.h $(DIR_O)/MarginView.obj: \ ../src/MarginView.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ ../include/Scintilla.h \ ../src/CharacterCategory.h \ ../src/Position.h \ - ../src/IntegerRectangle.h \ ../src/UniqueString.h \ ../src/SplitVector.h \ ../src/Partitioning.h \ @@ -295,7 +316,9 @@ $(DIR_O)/MarginView.obj: \ ../src/EditView.h $(DIR_O)/PerLine.obj: \ ../src/PerLine.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/Position.h \ @@ -305,7 +328,9 @@ $(DIR_O)/PerLine.obj: \ ../src/PerLine.h $(DIR_O)/PositionCache.obj: \ ../src/PositionCache.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ @@ -337,7 +362,7 @@ $(DIR_O)/RESearch.obj: \ ../src/RESearch.h $(DIR_O)/RunStyles.obj: \ ../src/RunStyles.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/Position.h \ @@ -346,7 +371,9 @@ $(DIR_O)/RunStyles.obj: \ ../src/RunStyles.h $(DIR_O)/ScintillaBase.obj: \ ../src/ScintillaBase.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ @@ -379,7 +406,9 @@ $(DIR_O)/ScintillaBase.obj: \ ../src/ScintillaBase.h $(DIR_O)/ScintillaBaseL.obj: \ ../src/ScintillaBase.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/ILoader.h \ ../include/Sci_Position.h \ ../include/ILexer.h \ @@ -412,14 +441,16 @@ $(DIR_O)/ScintillaBaseL.obj: \ ../src/ScintillaBase.h $(DIR_O)/Selection.obj: \ ../src/Selection.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/Position.h \ ../src/Selection.h $(DIR_O)/Style.obj: \ ../src/Style.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/Style.h @@ -431,7 +462,9 @@ $(DIR_O)/UniqueString.obj: \ ../src/UniqueString.h $(DIR_O)/ViewStyle.obj: \ ../src/ViewStyle.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../include/Scintilla.h \ ../include/Sci_Position.h \ ../src/Position.h \ @@ -443,5 +476,7 @@ $(DIR_O)/ViewStyle.obj: \ ../src/ViewStyle.h $(DIR_O)/XPM.obj: \ ../src/XPM.cxx \ - ../include/Platform.h \ + ../src/Debugging.h \ + ../src/Geometry.h \ + ../src/Platform.h \ ../src/XPM.h diff --git a/scintilla/win32/scintilla.mak b/scintilla/win32/scintilla.mak index 7a7fb89da..edb0c7de8 100644 --- a/scintilla/win32/scintilla.mak +++ b/scintilla/win32/scintilla.mak @@ -89,6 +89,7 @@ SRC_OBJS=\ $(DIR_O)\EditModel.obj \ $(DIR_O)\Editor.obj \ $(DIR_O)\EditView.obj \ + $(DIR_O)\Geometry.obj \ $(DIR_O)\Indicator.obj \ $(DIR_O)\KeyMap.obj \ $(DIR_O)\LineMarker.obj \ diff --git a/src/Dialogs.c b/src/Dialogs.c index fa1e8e79c..163c2f146 100644 --- a/src/Dialogs.c +++ b/src/Dialogs.c @@ -227,7 +227,7 @@ static INT_PTR CALLBACK _InfoBoxLngDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, { static HBITMAP hIconBmp = NULL; static HICON hBoxIcon = NULL; - static DPI_T dpi = {USER_DEFAULT_SCREEN_DPI, USER_DEFAULT_SCREEN_DPI}; + static UINT dpi = USER_DEFAULT_SCREEN_DPI; switch (umsg) { case WM_INITDIALOG: { @@ -296,15 +296,14 @@ static INT_PTR CALLBACK _InfoBoxLngDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, case WM_DPICHANGED: { - dpi.x = LOWORD(wParam); - dpi.y = HIWORD(wParam); + dpi = LOWORD(wParam); int const scxb = Scintilla_GetSystemMetricsForDpi(SM_CXICON, dpi); int const scyb = Scintilla_GetSystemMetricsForDpi(SM_CYICON, dpi); hIconBmp = ResampleIconToBitmap(hwnd, hIconBmp, hBoxIcon, scxb, scyb); if (hIconBmp) { SetBitmapControl(hwnd, IDC_INFOBOXICON, hIconBmp); } - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); } return TRUE; @@ -757,7 +756,7 @@ static INT_PTR CALLBACK CmdLineHelpProc(HWND hwnd, UINT umsg, WPARAM wParam, LPA return TRUE; case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); return TRUE; #ifdef D_NP3_WIN10_DARK_MODE @@ -958,7 +957,7 @@ INT_PTR CALLBACK AboutDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam static HFONT hVersionFont = NULL; static char pAboutResource[8192] = { '\0' }; static char* pAboutInfo = NULL; - static DPI_T dpi = { 0, 0 }; + static UINT dpi = USER_DEFAULT_SCREEN_DPI; static HBRUSH hbrBkgnd = NULL; switch (umsg) { @@ -1064,15 +1063,15 @@ INT_PTR CALLBACK AboutDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam } SendDlgItemMessage(hwnd, IDC_RICHEDITABOUT, EM_STREAMIN, SF_RTF, (LPARAM)&editStreamIn); } - SendDlgItemMessage(hwnd, IDC_RICHEDITABOUT, EM_SHOWSCROLLBAR, SB_HORZ, (LPARAM)(dpi.y > USER_DEFAULT_SCREEN_DPI)); + SendDlgItemMessage(hwnd, IDC_RICHEDITABOUT, EM_SHOWSCROLLBAR, SB_HORZ, (LPARAM)(dpi > USER_DEFAULT_SCREEN_DPI)); // RichEdit-Ctrl DPI-BUG: it initially uses the DPI setting of // the main(1) screen instead it's current parent window screen DPI - DPI_T const dpiPrime = Scintilla_GetWindowDPI(NULL); - SendDlgItemMessage(hwnd, IDC_RICHEDITABOUT, EM_SETZOOM, (WPARAM)dpi.y, (LPARAM)dpiPrime.y); + UINT const dpiPrime = Scintilla_GetWindowDPI(NULL); + SendDlgItemMessage(hwnd, IDC_RICHEDITABOUT, EM_SETZOOM, (WPARAM)dpi, (LPARAM)dpiPrime); - int const width = ScaleIntByDPI(136, dpi.x); - int const height = ScaleIntByDPI(41, dpi.y); + int const width = ScaleIntByDPI(136, dpi); + int const height = ScaleIntByDPI(41, dpi); HBITMAP hBmp = LoadImage(Globals.hInstance, MAKEINTRESOURCE(IDR_RIZBITMAP), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); SetBitmapControlResample(hwnd, IDC_RIZONEBMP, hBmp, width, height); DeleteObject(hBmp); @@ -1087,8 +1086,8 @@ INT_PTR CALLBACK AboutDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam break; case WM_DPICHANGED: { - dpi.x = LOWORD(wParam); - dpi.y = HIWORD(wParam); + dpi = LOWORD(wParam); + //dpi.y = HIWORD(wParam); // render rich-edit control text again if (!StrIsEmptyA(pAboutResource)) { @@ -1099,11 +1098,11 @@ INT_PTR CALLBACK AboutDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam } SendDlgItemMessage(hwnd, IDC_RICHEDITABOUT, EM_STREAMIN, SF_RTF, (LPARAM)&editStreamIn); } - SendDlgItemMessage(hwnd, IDC_RICHEDITABOUT, EM_SHOWSCROLLBAR, SB_HORZ, (LPARAM)(dpi.y > USER_DEFAULT_SCREEN_DPI)); + SendDlgItemMessage(hwnd, IDC_RICHEDITABOUT, EM_SHOWSCROLLBAR, SB_HORZ, (LPARAM)(dpi > USER_DEFAULT_SCREEN_DPI)); //~SendDlgItemMessage(hwnd, IDC_RICHEDITABOUT, EM_SETZOOM, (WPARAM)dpi.y, (LPARAM)USER_DEFAULT_SCREEN_DPI); - int const width = ScaleIntByDPI(136, dpi.x); - int const height = ScaleIntByDPI(41, dpi.y); + int const width = ScaleIntByDPI(136, dpi); + int const height = ScaleIntByDPI(41, dpi); HBITMAP hBmp = LoadImage(Globals.hInstance, MAKEINTRESOURCE(IDR_RIZBITMAP), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); SetBitmapControlResample(hwnd, IDC_RIZONEBMP, hBmp, width, height); DeleteObject(hBmp); @@ -1122,7 +1121,7 @@ INT_PTR CALLBACK AboutDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam SendDlgItemMessageW(hwnd, IDC_VERSION, WM_SETFONT, (WPARAM)hVersionFont, true); } - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); } break; @@ -1179,13 +1178,13 @@ CASE_WM_CTLCOLOR_SET: SetMapMode(hdc, MM_TEXT); int const iconSize = 128; - int const dpiWidth = ScaleIntByDPI(iconSize, dpi.x); - int const dpiHeight = ScaleIntByDPI(iconSize, dpi.y); + int const dpiWidth = ScaleIntByDPI(iconSize, dpi); + int const dpiHeight = ScaleIntByDPI(iconSize, dpi); HICON const hicon = (dpiHeight > 128) ? Globals.hDlgIcon256 : Globals.hDlgIcon128; if (hicon) { //RECT rc = {0}; //MapWindowPoints(GetDlgItem(hwnd, IDC_INFO_GROUPBOX), hwnd, (LPPOINT)&rc, 2); - DrawIconEx(hdc, ScaleIntByDPI(10, dpi.x), ScaleIntByDPI(10, dpi.x), hicon, dpiWidth, dpiHeight, 0, NULL, DI_NORMAL); + DrawIconEx(hdc, ScaleIntByDPI(10, dpi), ScaleIntByDPI(10, dpi), hicon, dpiWidth, dpiHeight, 0, NULL, DI_NORMAL); } ReleaseDC(hwnd, hdc); @@ -1305,7 +1304,7 @@ CASE_WM_CTLCOLOR_SET: StringCchPrintf(wchBuf, COUNTOF(wchBuf), L"\n- Screen-Resolution -> %i x %i [pix]", ResX, ResY); StringCchCat(wchVerInfo, COUNTOF(wchVerInfo), wchBuf); - StringCchPrintf(wchBuf, COUNTOF(wchBuf), L"\n- Display-DPI -> %i x %i (Scale: %i%%).", dpi.x, dpi.y, ScaleIntToDPI_X(hwnd, 100)); + StringCchPrintf(wchBuf, COUNTOF(wchBuf), L"\n- Display-DPI -> %i x %i (Scale: %i%%).", dpi, dpi, ScaleIntToDPI(hwnd, 100)); StringCchCat(wchVerInfo, COUNTOF(wchVerInfo), wchBuf); StringCchPrintf(wchBuf, COUNTOF(wchBuf), L"\n- Rendering-Technology -> '%s'", Settings.RenderingTechnology ? L"DIRECT-WRITE" : L"GDI"); @@ -1370,7 +1369,7 @@ static INT_PTR CALLBACK RunDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM l case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); return TRUE; @@ -1588,7 +1587,7 @@ static INT_PTR CALLBACK OpenWithDlgProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARAM case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); return TRUE; @@ -1821,7 +1820,7 @@ static INT_PTR CALLBACK FavoritesDlgProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARA case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); return TRUE; @@ -2026,7 +2025,7 @@ static INT_PTR CALLBACK AddToFavDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, LPA case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); break; @@ -2306,7 +2305,7 @@ static INT_PTR CALLBACK FileMRUDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, LPAR return TRUE; case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); return TRUE; case WM_DESTROY: { @@ -2725,7 +2724,7 @@ static INT_PTR CALLBACK ChangeNotifyDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, return TRUE; case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); return TRUE; #ifdef D_NP3_WIN10_DARK_MODE @@ -2883,7 +2882,7 @@ static INT_PTR CALLBACK ColumnWrapDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, L case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); return TRUE; @@ -3030,7 +3029,7 @@ static INT_PTR CALLBACK WordWrapSettingsDlgProc(HWND hwnd, UINT umsg, WPARAM wPa case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); return TRUE; @@ -3174,7 +3173,7 @@ static INT_PTR CALLBACK LongLineSettingsDlgProc(HWND hwnd, UINT umsg, WPARAM wPa case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); return TRUE; @@ -3332,7 +3331,7 @@ static INT_PTR CALLBACK TabSettingsDlgProc(HWND hwnd,UINT umsg,WPARAM wParam,LPA case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); return TRUE; @@ -3507,7 +3506,7 @@ static INT_PTR CALLBACK SelectDefEncodingDlgProc(HWND hwnd, UINT umsg, WPARAM wP case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); return TRUE; @@ -3704,7 +3703,7 @@ static INT_PTR CALLBACK SelectEncodingDlgProc(HWND hwnd,UINT umsg,WPARAM wParam, case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); return TRUE; @@ -3934,7 +3933,7 @@ static INT_PTR CALLBACK SelectDefLineEndingDlgProc(HWND hwnd,UINT umsg,WPARAM wP case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); return TRUE; @@ -5128,7 +5127,7 @@ void GetDlgPos(HWND hDlg, LPINT xDlg, LPINT yDlg) return; } - DPI_T const dpi = Scintilla_GetWindowDPI(hDlg); + UINT const dpi = Scintilla_GetWindowDPI(hDlg); RECT rcDlg; GetWindowRect(hDlg, &rcDlg); @@ -5139,10 +5138,10 @@ void GetDlgPos(HWND hDlg, LPINT xDlg, LPINT yDlg) // return positions relative to parent window (normalized DPI) if (xDlg) { - *xDlg = MulDiv((rcDlg.left - rcParent.left), USER_DEFAULT_SCREEN_DPI, (dpi.x ? dpi.x : USER_DEFAULT_SCREEN_DPI)); + *xDlg = MulDiv((rcDlg.left - rcParent.left), USER_DEFAULT_SCREEN_DPI, (dpi ? dpi : USER_DEFAULT_SCREEN_DPI)); } if (yDlg) { - *yDlg = MulDiv((rcDlg.top - rcParent.top), USER_DEFAULT_SCREEN_DPI, (dpi.y ? dpi.y : USER_DEFAULT_SCREEN_DPI)); + *yDlg = MulDiv((rcDlg.top - rcParent.top), USER_DEFAULT_SCREEN_DPI, (dpi ? dpi : USER_DEFAULT_SCREEN_DPI)); } } @@ -5157,7 +5156,7 @@ void SetDlgPos(HWND hDlg, int xDlg, int yDlg) return; } - DPI_T const dpi = Scintilla_GetWindowDPI(hDlg); + UINT const dpi = Scintilla_GetWindowDPI(hDlg); RECT rcDlg; GetWindowRect(hDlg, &rcDlg); @@ -5178,8 +5177,8 @@ void SetDlgPos(HWND hDlg, int xDlg, int yDlg) int const yMax = (mi.rcWork.bottom) - (rcDlg.bottom - rcDlg.top); // desired positions relative to parent window (normalized DPI) - int const x = rcParent.left + MulDiv(xDlg, dpi.x, USER_DEFAULT_SCREEN_DPI); - int const y = rcParent.top + MulDiv(yDlg, dpi.y, USER_DEFAULT_SCREEN_DPI); + int const x = rcParent.left + MulDiv(xDlg, dpi, USER_DEFAULT_SCREEN_DPI); + int const y = rcParent.top + MulDiv(yDlg, dpi, USER_DEFAULT_SCREEN_DPI); SetWindowPos(hDlg, NULL, clampi(x, xMin, xMax), clampi(y, yMin, yMax), 0, 0, SWP_NOZORDER | SWP_NOSIZE); } @@ -5197,7 +5196,7 @@ void SetDlgPos(HWND hDlg, int xDlg, int yDlg) typedef struct _resizeDlg { int direction; - DPI_T dpi; + UINT dpi; int cxClient; int cyClient; int mmiPtMinX; @@ -5222,16 +5221,7 @@ void ResizeDlg_InitEx(HWND hwnd, int cxFrame, int cyFrame, int nIdGrip, RSZ_DLG_ const DWORD style = (pm->direction < 0) ? (GetWindowStyle(hwnd) & ~WS_THICKFRAME) : (GetWindowStyle(hwnd) | WS_THICKFRAME); - WRCT_T wrc = { 0 }; - wrc.left = rc.left; - wrc.top = rc.top; - wrc.right = rc.right; - wrc.bottom = rc.bottom; - Scintilla_AdjustWindowRectForDpi(&wrc, style, 0, pm->dpi); - rc.left = wrc.left; - rc.top = wrc.top; - rc.right = wrc.right; - rc.bottom = wrc.bottom; + Scintilla_AdjustWindowRectForDpi((LPWRECT)&rc, style, 0, pm->dpi); pm->mmiPtMinX = rc.right - rc.left; pm->mmiPtMinY = rc.bottom - rc.top; @@ -5294,17 +5284,17 @@ void ResizeDlg_Size(HWND hwnd, LPARAM lParam, int* cx, int* cy) const int cxClient = LOWORD(lParam); const int cyClient = HIWORD(lParam); #if NP3_ENABLE_RESIZEDLG_TEMP_FIX - const DPI_T dpi = Scintilla_GetWindowDPI(hwnd); - const DPI_T old = pm->dpi; + const UINT dpi = Scintilla_GetWindowDPI(hwnd); + const UINT old = pm->dpi; if (cx) { - *cx = cxClient - MulDiv(pm->cxClient, dpi.x, old.x); + *cx = cxClient - MulDiv(pm->cxClient, dpi, old); } if (cy) { - *cy = cyClient - MulDiv(pm->cyClient, dpi.y, old.y); + *cy = cyClient - MulDiv(pm->cyClient, dpi, old); } // store in original DPI. - pm->cxClient = MulDiv(cxClient, old.x, dpi.x); - pm->cyClient = MulDiv(cyClient, old.y, dpi.y); + pm->cxClient = MulDiv(cxClient, old, dpi); + pm->cyClient = MulDiv(cyClient, old, dpi); #else if (cx) { *cx = cxClient - pm->cxClient; @@ -5322,20 +5312,20 @@ void ResizeDlg_GetMinMaxInfo(HWND hwnd, LPARAM lParam) LPCRESIZEDLG pm = (LPCRESIZEDLG)GetProp(hwnd, RESIZEDLG_PROP_KEY); LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; #if NP3_ENABLE_RESIZEDLG_TEMP_FIX - DPI_T const dpi = Scintilla_GetWindowDPI(hwnd); - DPI_T const old = pm->dpi; + UINT const dpi = Scintilla_GetWindowDPI(hwnd); + UINT const old = pm->dpi; - lpmmi->ptMinTrackSize.x = MulDiv(pm->mmiPtMinX, dpi.x, old.x); - lpmmi->ptMinTrackSize.y = MulDiv(pm->mmiPtMinY, dpi.y, old.y); + lpmmi->ptMinTrackSize.x = MulDiv(pm->mmiPtMinX, dpi, old); + lpmmi->ptMinTrackSize.y = MulDiv(pm->mmiPtMinY, dpi, old); // only one direction switch (pm->direction) { case RSZ_ONLY_X: - lpmmi->ptMaxTrackSize.y = MulDiv(pm->mmiPtMaxY, dpi.x, old.x); + lpmmi->ptMaxTrackSize.y = MulDiv(pm->mmiPtMaxY, dpi, old); break; case RSZ_ONLY_Y: - lpmmi->ptMaxTrackSize.x = MulDiv(pm->mmiPtMaxX, dpi.y, old.y); + lpmmi->ptMaxTrackSize.x = MulDiv(pm->mmiPtMaxX, dpi, old); break; } #else @@ -5392,9 +5382,9 @@ int ResizeDlg_CalcDeltaY2(HWND hwnd, int dy, int cy, int nCtlId1, int nCtlId2) } const LPCRESIZEDLG pm = (LPCRESIZEDLG)GetProp(hwnd, RESIZEDLG_PROP_KEY); #if NP3_ENABLE_RESIZEDLG_TEMP_FIX - DPI_T const dpi = Scintilla_GetWindowDPI(hwnd); - int const hMinX = MulDiv(pm->attrs[0], dpi.x, pm->dpi.x); - int const hMinY = MulDiv(pm->attrs[1], dpi.y, pm->dpi.y); + UINT const dpi = Scintilla_GetWindowDPI(hwnd); + int const hMinX = MulDiv(pm->attrs[0], dpi, pm->dpi); + int const hMinY = MulDiv(pm->attrs[1], dpi, pm->dpi); #else int const hMinX = pm->attrs[0]; int const hMinY = pm->attrs[1]; @@ -5701,12 +5691,11 @@ int Toolbar_SetButtons(HANDLE hwnd, int cmdBase, LPCWSTR lpszButtons, LPCTBBUTTO // GetCurrentPPI() // (font size) points per inch // -DPI_T GetCurrentPPI(HWND hwnd) -{ +UINT GetCurrentPPI(HWND hwnd) { HDC const hDC = GetDC(hwnd); - DPI_T ppi = { 0, 0 }; - ppi.x = max_u(GetDeviceCaps(hDC, LOGPIXELSX), USER_DEFAULT_SCREEN_DPI); - ppi.y = max_u(GetDeviceCaps(hDC, LOGPIXELSY), USER_DEFAULT_SCREEN_DPI); + UINT ppi = 0; + //ppi.x = max_u(GetDeviceCaps(hDC, LOGPIXELSX), USER_DEFAULT_SCREEN_DPI); + ppi = max_u(GetDeviceCaps(hDC, LOGPIXELSY), USER_DEFAULT_SCREEN_DPI); ReleaseDC(hwnd, hDC); return ppi; } @@ -5761,7 +5750,7 @@ bool GetThemedDialogFont(LPWSTR lpFaceName, WORD* wSize) if (!bSucceed) { if (IsAppThemed()) { - unsigned const iLogPixelsY = GetCurrentPPI(NULL).y - DIALOG_FONT_SIZE_INCR; + unsigned const iLogPixelsY = GetCurrentPPI(NULL) - DIALOG_FONT_SIZE_INCR; HTHEME hTheme = OpenThemeData(NULL, L"WINDOWSTYLE;WINDOW"); if (hTheme) { @@ -5782,7 +5771,7 @@ bool GetThemedDialogFont(LPWSTR lpFaceName, WORD* wSize) } if (!bSucceed) { - unsigned const iLogPixelsY = GetCurrentPPI(NULL).y - DIALOG_FONT_SIZE_INCR; + unsigned const iLogPixelsY = GetCurrentPPI(NULL) - DIALOG_FONT_SIZE_INCR; NONCLIENTMETRICS ncm = { 0 }; ncm.cbSize = sizeof(NONCLIENTMETRICS) - sizeof(ncm.iPaddedBorderWidth); @@ -6033,12 +6022,12 @@ HBITMAP ResampleIconToBitmap(HWND hwnd, HBITMAP hOldBmp, const HICON hIcon, cons // void SetUACIcon(HWND hwnd, const HMENU hMenu, const UINT nItem) { - static DPI_T dpi = { 0, 0 }; + static UINT dpi = USER_DEFAULT_SCREEN_DPI; static MENUITEMINFO mii = { 0 }; - DPI_T const cur_dpi = Scintilla_GetWindowDPI(hwnd); + UINT const cur_dpi = Scintilla_GetWindowDPI(hwnd); - if ((dpi.x != cur_dpi.x) || (dpi.y != cur_dpi.y)) { + if (dpi != cur_dpi) { dpi = cur_dpi; int const scx = Scintilla_GetSystemMetricsForDpi(SM_CXSMICON, dpi); int const scy = Scintilla_GetSystemMetricsForDpi(SM_CYSMICON, dpi); @@ -6064,35 +6053,24 @@ void SetUACIcon(HWND hwnd, const HMENU hMenu, const UINT nItem) // // UpdateWindowLayoutForDPI() // -inline WRCT_T _ConvWinRectW(const RECT* pRC) -{ - WRCT_T wrc; - wrc.left = pRC->left; - wrc.top = pRC->top; - wrc.right = pRC->right; - wrc.bottom = pRC->bottom; - return wrc; -} +void UpdateWindowLayoutForDPI(HWND hwnd, const RECT *pNewRect, const UINT adpi) { -void UpdateWindowLayoutForDPI(HWND hwnd, const RECT* prc, const DPI_T* pdpi) -{ UINT const uWndFlags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED; //~ SWP_NOMOVE | SWP_NOSIZE | SWP_NOREPOSITION - if (prc) { - SetWindowPos(hwnd, NULL, prc->left, prc->top, (prc->right - prc->left), (prc->bottom - prc->top), uWndFlags); - return; + if (pNewRect) { + SetWindowPos(hwnd, NULL, pNewRect->left, pNewRect->top, + (pNewRect->right - pNewRect->left), (pNewRect->bottom - pNewRect->top), uWndFlags); + } else { + RECT rc = { 0 }; + GetWindowRect(hwnd, &rc); + //~MapWindowPoints(NULL, hWnd, (LPPOINT)&rc, 2); + UINT const dpi = adpi ? adpi : Scintilla_GetWindowDPI(hwnd); + Scintilla_AdjustWindowRectForDpi((LPWRECT)&rc, uWndFlags, 0, dpi); + SetWindowPos(hwnd, NULL, rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top), uWndFlags); } - - DPI_T const dpi = pdpi ? *pdpi : Scintilla_GetWindowDPI(hwnd); - - RECT rc; - GetWindowRect(hwnd, &rc); - //~MapWindowPoints(NULL, hWnd, (LPPOINT)&rc, 2); - WRCT_T wrc = _ConvWinRectW(prc); - Scintilla_AdjustWindowRectForDpi(&wrc, uWndFlags, 0, dpi); - SetWindowPos(hwnd, NULL, wrc.left, wrc.top, (wrc.right - wrc.left), (wrc.bottom - wrc.top), uWndFlags); } + //============================================================================= // // ResampleImageBitmap() (resample_delete_orig) @@ -6104,9 +6082,9 @@ HBITMAP ResampleImageBitmap(HWND hwnd, HBITMAP hbmp, int width, int height) BITMAP bmp = { 0 }; if (GetObject(hbmp, sizeof(BITMAP), &bmp)) { if ((width <= 0) || (height <= 0)) { - DPI_T const dpi = Scintilla_GetWindowDPI(hwnd); - width = ScaleIntByDPI(bmp.bmWidth, dpi.x); - height = ScaleIntByDPI(bmp.bmHeight, dpi.y); + UINT const dpi = Scintilla_GetWindowDPI(hwnd); + width = ScaleIntByDPI(bmp.bmWidth, dpi); + height = ScaleIntByDPI(bmp.bmHeight, dpi); } if (((LONG)width != bmp.bmWidth) || ((LONG)height != bmp.bmHeight)) { #if TRUE @@ -6153,8 +6131,8 @@ HFONT CreateAndSetFontDlgItemDPI(HWND hdlg, const int idDlgItem, int fontSize, b ncm.cbSize = sizeof(NONCLIENTMETRICSW); if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &ncm, 0)) { HDC const hdcSys = GetDC(NULL); - DPI_T const dpiSys = Scintilla_GetWindowDPI(NULL); - DPI_T const dpiDlg = Scintilla_GetWindowDPI(hdlg); + UINT const dpiSys = Scintilla_GetWindowDPI(NULL); + UINT const dpiDlg = Scintilla_GetWindowDPI(hdlg); if (fontSize <= 0) { fontSize = (ncm.lfMessageFont.lfHeight < 0) ? -ncm.lfMessageFont.lfHeight : ncm.lfMessageFont.lfHeight; if (fontSize == 0) { @@ -6163,7 +6141,7 @@ HFONT CreateAndSetFontDlgItemDPI(HWND hdlg, const int idDlgItem, int fontSize, b } fontSize <<= 10; // precision fontSize = MulDiv(fontSize, USER_DEFAULT_SCREEN_DPI, dpiSys.y); // correction - fontSize = ScaleIntByDPI(fontSize, dpiDlg.y); + fontSize = ScaleIntByDPI(fontSize, dpiDlg); ncm.lfMessageFont.lfHeight = -(MulDiv(fontSize, GetDeviceCaps(hdcSys, LOGPIXELSY), 72) >> 10); ncm.lfMessageFont.lfWeight = bold ? FW_BOLD : FW_NORMAL; HFONT const hFont = CreateFontIndirectW(&ncm.lfMessageFont); diff --git a/src/Dialogs.h b/src/Dialogs.h index 5e9bcaa5f..33398de6e 100644 --- a/src/Dialogs.h +++ b/src/Dialogs.h @@ -181,36 +181,26 @@ inline int GetDlgCtrlHeight(HWND hwndDlg, int nCtrlId) return (rc.bottom - rc.top); } -DPI_T GetCurrentPPI(HWND hwnd); +UINT GetCurrentPPI(HWND hwnd); inline int ScaleIntByDPI(int val, unsigned dpi) { return MulDiv(val, dpi, USER_DEFAULT_SCREEN_DPI); } -inline int ScaleIntToDPI_X(HWND hwnd, int val) +inline int ScaleIntToDPI(HWND hwnd, int val) { - DPI_T const dpi = Scintilla_GetWindowDPI(hwnd); - return ScaleIntByDPI(val, dpi.x); -} -inline int ScaleIntToDPI_Y(HWND hwnd, int val) -{ - DPI_T const dpi = Scintilla_GetWindowDPI(hwnd); - return ScaleIntByDPI(val, dpi.y); + UINT const dpi = Scintilla_GetWindowDPI(hwnd); + return ScaleIntByDPI(val, dpi); } inline int ScaleFloatByDPI(float fVal, unsigned dpi) { return (int)lroundf((fVal * dpi) / (float)USER_DEFAULT_SCREEN_DPI); } -inline int ScaleFloatToDPI_X(HWND hwnd, float fVal) +inline int ScaleFloatToDPI(HWND hwnd, float fVal) { - DPI_T const dpi = Scintilla_GetWindowDPI(hwnd); - return ScaleFloatByDPI(fVal, dpi.x); -} -inline int ScaleFloatToDPI_Y(HWND hwnd, float fVal) -{ - DPI_T const dpi = Scintilla_GetWindowDPI(hwnd); - return ScaleFloatByDPI(fVal, dpi.y); + UINT const dpi = Scintilla_GetWindowDPI(hwnd); + return ScaleFloatByDPI(fVal, dpi); } inline unsigned LargeIconDPI() @@ -223,9 +213,9 @@ inline unsigned LargeIconDPI() HBITMAP ConvertIconToBitmap(const HICON hIcon, const int cx, const int cy); HBITMAP ResampleIconToBitmap(HWND hwnd, HBITMAP hOldBmp, const HICON hIcon, const int cx, const int cy); void SetUACIcon(HWND hwnd, const HMENU hMenu, const UINT nItem); -void UpdateWindowLayoutForDPI(HWND hwnd, const RECT* pRC, const DPI_T* pDPI); -//#define HandleDpiChangedMessage(hW,wP,lP) { DPI_T dpi; dpi.x = LOWORD(wP); dpi.y = HIWORD(wP); \ -// UpdateWindowLayoutForDPI(hW, (RECT*)lP, &dpi); } +void UpdateWindowLayoutForDPI(HWND hwnd, const RECT *pRC, const UINT dpi); +//#define HandleDpiChangedMessage(hW,wP,lP) { UINT dpi; dpi = LOWORD(wP); /*dpi = HIWORD(wP);*/ \ +// UpdateWindowLayoutForDPI(hW, (RECT*)lP, dpi); } # define BMP_RESAMPLE_FILTER STOCK_FILTER_LANCZOS8 //#define BMP_RESAMPLE_FILTER STOCK_FILTER_QUADRATICBSPLINE diff --git a/src/Edit.c b/src/Edit.c index fe89a84e4..789f53c1f 100644 --- a/src/Edit.c +++ b/src/Edit.c @@ -6049,10 +6049,8 @@ static INT_PTR CALLBACK EditFindReplaceDlgProc(HWND hwnd, UINT umsg, WPARAM wPar case WM_DPICHANGED: { - DPI_T dpi = { 0, 0 }; - dpi.x = LOWORD(wParam); - dpi.y = HIWORD(wParam); - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, &dpi); + UINT const dpi = LOWORD(wParam); + UpdateWindowLayoutForDPI(hwnd, (RECT *)lParam, dpi); } return TRUE; // further processing @@ -8018,10 +8016,8 @@ static INT_PTR CALLBACK EditLinenumDlgProc(HWND hwnd,UINT umsg,WPARAM wParam,LPA case WM_DPICHANGED: { - DPI_T dpi = { 0, 0 }; - dpi.x = LOWORD(wParam); - dpi.y = HIWORD(wParam); - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, &dpi); + UINT const dpi = LOWORD(wParam); + UpdateWindowLayoutForDPI(hwnd, (RECT *)lParam, dpi); } return true; @@ -8200,10 +8196,7 @@ static INT_PTR CALLBACK EditModifyLinesDlgProc(HWND hwnd,UINT umsg,WPARAM wParam return true; case WM_DPICHANGED: { - DPI_T dpi = { 0, 0 }; - dpi.x = LOWORD(wParam); - dpi.y = HIWORD(wParam); - + //UINT const dpi = LOWORD(wParam); HFONT const hFont = (HFONT)SendDlgItemMessage(hwnd, 200, WM_GETFONT, 0, 0); if (hFont) { LOGFONT lf = { 0 }; @@ -8215,8 +8208,8 @@ static INT_PTR CALLBACK EditModifyLinesDlgProc(HWND hwnd,UINT umsg,WPARAM wParam } hFontHover = CreateFontIndirectW(&lf); } - - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, &dpi); + //@@@UpdateWindowLayoutForDPI(hwnd, NULL, dpi); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); } return TRUE; @@ -8429,7 +8422,7 @@ static INT_PTR CALLBACK EditAlignDlgProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARA return true; case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); return true; #ifdef D_NP3_WIN10_DARK_MODE @@ -8550,7 +8543,7 @@ static INT_PTR CALLBACK EditEncloseSelectionDlgProc(HWND hwnd,UINT umsg,WPARAM w return TRUE; case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); return TRUE; #ifdef D_NP3_WIN10_DARK_MODE @@ -8678,7 +8671,7 @@ static INT_PTR CALLBACK EditInsertTagDlgProc(HWND hwnd,UINT umsg,WPARAM wParam,L return false; case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); return true; #ifdef D_NP3_WIN10_DARK_MODE @@ -8901,7 +8894,7 @@ static INT_PTR CALLBACK EditSortDlgProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARAM return true; case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); return true; #ifdef D_NP3_WIN10_DARK_MODE diff --git a/src/Notepad3.c b/src/Notepad3.c index e5bca860e..d78257517 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -867,7 +867,7 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, //SetProcessDPIAware(); -> .manifest //SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE); - Scintilla_LoadDpiForWindow(); + //~Scintilla_LoadDpiForWindow(); done in Sci::Platform_Initialize(); // ---------------------------------------------------- // MultiLingual @@ -2416,16 +2416,14 @@ static HIMAGELIST CreateScaledImageListFromBitmap(HWND hWnd, HBITMAP hBmp) HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR32 | ILC_MASK, NUMTOOLBITMAPS, NUMTOOLBITMAPS); ImageList_AddMasked(himl, hBmp, CLR_DEFAULT); - DPI_T dpi = Scintilla_GetWindowDPI(hWnd); - if (!Settings.DpiScaleToolBar || - ((dpi.x == USER_DEFAULT_SCREEN_DPI) && (dpi.y == USER_DEFAULT_SCREEN_DPI))) { + UINT const dpi = Scintilla_GetWindowDPI(hWnd); + if (!Settings.DpiScaleToolBar || (dpi == USER_DEFAULT_SCREEN_DPI)) { return himl; // default DPI, we are done } - // Scale button icons/images - int const scx = ScaleIntToDPI_X(hWnd, cx); - int const scy = ScaleIntToDPI_Y(hWnd, cy); + int const scx = ScaleIntToDPI(hWnd, cx); + int const scy = ScaleIntToDPI(hWnd, cy); HIMAGELIST hsciml = ImageList_Create(scx, scy, ILC_COLOR32 | ILC_MASK | ILC_HIGHQUALITYSCALE, NUMTOOLBITMAPS, NUMTOOLBITMAPS); @@ -2461,8 +2459,8 @@ void CreateBars(HWND hwnd, HINSTANCE hInstance) DWORD dwToolbarExStyle = TBSTYLE_EX_DOUBLEBUFFER /* | TBSTYLE_EX_HIDECLIPPEDBUTTONS */; if (Settings.ToolBarTheme < 0) { // undefined: determine High DPI screen - DPI_T const dpi = Scintilla_GetWindowDPI(hwnd); - Settings.ToolBarTheme = (dpi.y < LargeIconDPI()) ? 0 : 1; + UINT const dpi = Scintilla_GetWindowDPI(hwnd); + Settings.ToolBarTheme = (dpi < LargeIconDPI()) ? 0 : 1; } if (Globals.hwndToolbar) { @@ -2794,15 +2792,13 @@ LRESULT MsgEndSession(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) // LRESULT MsgDPIChanged(HWND hwnd, WPARAM wParam, LPARAM lParam) { - //DPI_T dpi; - //dpi.x = LOWORD(wParam); - //dpi.y = HIWORD(wParam); + //UINT const dpi = LOWORD(wParam); UNREFERENCED_PARAMETER(wParam); //const RECT* const rc = (RECT*)lParam; DocPos const pos = SciCall_GetCurrentPos(); - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); SendMessage(Globals.hwndEdit, WM_DPICHANGED, wParam, lParam); diff --git a/src/Print.cpp b/src/Print.cpp index 77c338018..c27e7c397 100644 --- a/src/Print.cpp +++ b/src/Print.cpp @@ -93,7 +93,7 @@ static UINT_PTR CALLBACK _LPPrintHookProc(HWND hwnd, UINT uiMsg, WPARAM wParam, break; case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT *)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); break; #ifdef D_NP3_WIN10_DARK_MODE @@ -609,7 +609,7 @@ static UINT_PTR CALLBACK _LPSetupHookProc(HWND hwnd, UINT uiMsg, WPARAM wParam, break; case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hwnd, (RECT *)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT *)lParam, 0); break; #ifdef D_NP3_WIN10_DARK_MODE diff --git a/src/SciCall.h b/src/SciCall.h index b16a9d4eb..23dd61e59 100644 --- a/src/SciCall.h +++ b/src/SciCall.h @@ -461,7 +461,6 @@ DeclareSciCallV1(SetVScrollbar, SETVSCROLLBAR, bool, visible); // Style definition // DeclareSciCallR0(GetLexer, GETLEXER, int); -DeclareSciCallV1(SetLexer, SETLEXER, int, lexerid); // deprecated DeclareSciCallV01(SetILexer, SETILEXER, void*, lexerPtr); // ILexer5* DeclareSciCallV1(SetIdleStyling, SETIDLESTYLING, int, idlestyle); diff --git a/src/Styles.c b/src/Styles.c index 1a46760c5..b966192b8 100644 --- a/src/Styles.c +++ b/src/Styles.c @@ -42,7 +42,7 @@ extern COLORREF g_colorCustom[16]; // removed from project, not MUI language compatible with ChooseFont() -//~bool ChooseFontDirectWrite(HWND hwnd, const WCHAR* localeName, DPI_T dpi, LPCHOOSEFONT lpCF); +//~bool ChooseFontDirectWrite(HWND hwnd, const WCHAR* localeName, UINT dpi, LPCHOOSEFONT lpCF); // ---------------------------------------------------------------------------- @@ -1095,15 +1095,13 @@ void Style_SetLexer(HWND hwnd, PEDITLEXER pLexNew) SciCall_SetILexer(CreateLexer(pLexNew->lexerName)); int const iNewLexer = SciCall_GetLexer(); - if ((pLexNew->lexerID > SCLEX_NULL) && (iNewLexer != pLexNew->lexerID)) { #ifdef _DEBUG + if ((pLexNew->lexerID > SCLEX_NULL) && (iNewLexer != pLexNew->lexerID)) { WCHAR msg[256] = { L'\0' }; StringCchPrintf(msg, COUNTOF(msg), L"Failed to set desired Lexer (#%i), got Lexer #%i!", pLexNew->lexerID, iNewLexer); DbgMsgBoxLastError(msg, ERROR_DLL_INIT_FAILED); -#endif - // try to use old method - SciCall_SetLexer(pLexNew->lexerID); // mixing lexers might cause problems } +#endif // Lexer very specific styles Style_SetLexerSpecificProperties(pLexNew->lexerID); @@ -1800,7 +1798,7 @@ void Style_HighlightCurrentLine(HWND hwnd, int iHiLitCurLn) if (!Style_StrGetSizeInt(szValue, &iFrameSize)) { iFrameSize = 2; } - iFrameSize = max_i(1, ScaleIntToDPI_Y(hwnd, iFrameSize)); + iFrameSize = max_i(1, ScaleIntToDPI(hwnd, iFrameSize)); SciCall_SetCaretLineFrame(iFrameSize); } @@ -1822,7 +1820,7 @@ static int _GetMarkerMarginWidth(HWND hwnd) Style_StrGetSize(GetCurrentStdLexer()->Styles[STY_MARGIN].szValue, &fSize); // relative to LineNumber Style_StrGetSize(GetCurrentStdLexer()->Styles[STY_BOOK_MARK].szValue, &fSize); // settings float const zoomPercent = (float)SciCall_GetZoom(); - return ScaleFloatToDPI_X(hwnd, (fSize * zoomPercent) / 100.0f); + return ScaleFloatToDPI(hwnd, (fSize * zoomPercent) / 100.0f); } //============================================================================= @@ -3495,7 +3493,7 @@ bool Style_SelectFont(HWND hwnd,LPWSTR lpszStyle,int cchStyle, LPCWSTR sLexerNam } #else if (Settings.RenderingTechnology > 0) { - DPI_T const dpi = Scintilla_GetWindowDPI(hwnd); + UINT const dpi = Scintilla_GetWindowDPI(hwnd); const WCHAR* const localName = Settings2.PreferredLanguageLocaleName; if (!ChooseFontDirectWrite(Globals.hwndMain, localName, dpi, &cf) || StrIsEmpty(lf.lfFaceName)) { return false; @@ -4147,7 +4145,7 @@ INT_PTR CALLBACK Style_CustomizeSchemesDlgProc(HWND hwnd, UINT umsg, WPARAM wPar SetWindowTheme(GetDlgItem(hwnd, IDC_INFO_GROUPBOX), L"", L""); } #endif - DPI_T const dpi = Scintilla_GetWindowDPI(hwnd); + UINT const dpi = Scintilla_GetWindowDPI(hwnd); GetLngString(IDS_MUI_STYLEEDIT_HELP, tchTmpBuffer, COUNTOF(tchTmpBuffer)); SetDlgItemText(hwnd, IDC_STYLEEDIT_HELP, tchTmpBuffer); @@ -4174,7 +4172,7 @@ INT_PTR CALLBACK Style_CustomizeSchemesDlgProc(HWND hwnd, UINT umsg, WPARAM wPar TreeView_SetExtendedStyle(hwndTV, TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER); - UINT const flagIconSize = (dpi.y >= LargeIconDPI()) ? SHGFI_LARGEICON : SHGFI_SMALLICON; + UINT const flagIconSize = (dpi >= LargeIconDPI()) ? SHGFI_LARGEICON : SHGFI_SMALLICON; TreeView_SetImageList(hwndTV, (HIMAGELIST)SHGetFileInfoW(L"C:\\", FILE_ATTRIBUTE_DIRECTORY, &shfi, sizeof(SHFILEINFO), flagIconSize | SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES), @@ -4252,12 +4250,10 @@ INT_PTR CALLBACK Style_CustomizeSchemesDlgProc(HWND hwnd, UINT umsg, WPARAM wPar return TRUE; case WM_DPICHANGED: { - DPI_T dpi = { 0, 0 }; - dpi.x = LOWORD(wParam); - dpi.y = HIWORD(wParam); + UINT const dpi = LOWORD(wParam); SHFILEINFO shfi = { 0 }; - UINT const flagIconSize = (dpi.y >= LargeIconDPI()) ? SHGFI_LARGEICON : SHGFI_SMALLICON; + UINT const flagIconSize = (dpi >= LargeIconDPI()) ? SHGFI_LARGEICON : SHGFI_SMALLICON; TreeView_SetImageList(hwndTV, (HIMAGELIST)SHGetFileInfoW(L"C:\\", FILE_ATTRIBUTE_DIRECTORY, &shfi, sizeof(SHFILEINFO), flagIconSize | SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES), @@ -4282,7 +4278,7 @@ INT_PTR CALLBACK Style_CustomizeSchemesDlgProc(HWND hwnd, UINT umsg, WPARAM wPar MakeBitmapButton(hwnd, IDC_PREVSTYLE, IDB_PREV, -1, -1); MakeBitmapButton(hwnd, IDC_NEXTSTYLE, IDB_NEXT, -1, -1); - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); } return TRUE; @@ -4292,16 +4288,15 @@ INT_PTR CALLBACK Style_CustomizeSchemesDlgProc(HWND hwnd, UINT umsg, WPARAM wPar if (hdc) { BeginPaint(hwnd, &ps); - DPI_T const dpi = Scintilla_GetWindowDPI(hwnd); + UINT const dpi = Scintilla_GetWindowDPI(hwnd); int const iconSize = 64; - int const dpiWidth = ScaleIntByDPI(iconSize, dpi.x); - int const dpiHeight = ScaleIntByDPI(iconSize, dpi.y); - HICON const hicon = (dpiHeight > 128) ? Globals.hDlgIconPrefs256 : ((dpiHeight > 64) ? Globals.hDlgIconPrefs128 : Globals.hDlgIconPrefs64); + int const dpiSize = ScaleIntByDPI(iconSize, dpi); + HICON const hicon = (dpiSize > 128) ? Globals.hDlgIconPrefs256 : ((dpiSize > 64) ? Globals.hDlgIconPrefs128 : Globals.hDlgIconPrefs64); if (hicon) { RECT rc = {0}; MapWindowPoints(GetDlgItem(hwnd, IDC_INFO_GROUPBOX), hwnd, (LPPOINT)&rc, 2); - DrawIconEx(hdc, rc.left + ScaleIntByDPI(10, dpi.x), rc.top + ScaleIntByDPI(20, dpi.y), hicon, dpiWidth, dpiHeight, 0, NULL, DI_NORMAL); + DrawIconEx(hdc, rc.left + ScaleIntByDPI(10, dpi), rc.top + ScaleIntByDPI(20, dpi), hicon, dpiSize, dpiSize, 0, NULL, DI_NORMAL); } ReleaseDC(hwnd, hdc); @@ -4861,7 +4856,7 @@ INT_PTR CALLBACK Style_SelectLexerDlgProc(HWND hwnd,UINT umsg,WPARAM wParam,LPAR } #endif - DPI_T const dpi = Scintilla_GetWindowDPI(hwnd); + UINT const dpi = Scintilla_GetWindowDPI(hwnd); hwndLV = GetDlgItem(hwnd,IDC_STYLELIST); InitWindowCommon(hwndLV, true); @@ -4869,7 +4864,7 @@ INT_PTR CALLBACK Style_SelectLexerDlgProc(HWND hwnd,UINT umsg,WPARAM wParam,LPAR SHFILEINFO shfi = { 0 }; - UINT const flagIconSize = (dpi.y >= LargeIconDPI()) ? SHGFI_LARGEICON : SHGFI_SMALLICON; + UINT const flagIconSize = (dpi >= LargeIconDPI()) ? SHGFI_LARGEICON : SHGFI_SMALLICON; ListView_SetImageList(hwndLV, (HIMAGELIST)SHGetFileInfo(L"C:\\",FILE_ATTRIBUTE_DIRECTORY, &shfi, sizeof(SHFILEINFO), flagIconSize | SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES), @@ -4915,14 +4910,11 @@ INT_PTR CALLBACK Style_SelectLexerDlgProc(HWND hwnd,UINT umsg,WPARAM wParam,LPAR case WM_DPICHANGED: { - UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, NULL); - - DPI_T dpi = { 0, 0 }; - dpi.x = LOWORD(wParam); - dpi.y = HIWORD(wParam); + UpdateWindowLayoutForDPI(hwnd, (RECT*)lParam, 0); + UINT const dpi = LOWORD(wParam); SHFILEINFO shfi = { 0 }; - UINT const flagIconSize = (dpi.y >= LargeIconDPI()) ? SHGFI_LARGEICON : SHGFI_SMALLICON; + UINT const flagIconSize = (dpi >= LargeIconDPI()) ? SHGFI_LARGEICON : SHGFI_SMALLICON; ListView_SetImageList(hwndLV, (HIMAGELIST)SHGetFileInfo(L"C:\\", FILE_ATTRIBUTE_DIRECTORY, &shfi, sizeof(SHFILEINFO), flagIconSize | SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES), diff --git a/src/crypto/crypto.c b/src/crypto/crypto.c index ee2d1e904..ec6491600 100644 --- a/src/crypto/crypto.c +++ b/src/crypto/crypto.c @@ -153,11 +153,11 @@ INT_PTR CALLBACK SetKeysDlgProc(HWND hDlg, UINT umsg, WPARAM wParam, LPARAM lPar // Don't use: SetFocus( GetDlgItem( hDlg, IDC_PWD_EDIT1 ) ); SetDialogFocus(hDlg, GetDlgItem(hDlg, IDC_PWD_EDIT1)); } - return true; + return TRUE; case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hDlg, (RECT*)lParam, NULL); - return !0; + UpdateWindowLayoutForDPI(hDlg, (RECT*)lParam, 0); + return TRUE; //#define WM_CTLCOLORMSGBOX 0x0132 //#define WM_CTLCOLOREDIT 0x0133 @@ -352,7 +352,7 @@ INT_PTR CALLBACK GetKeysDlgProc(HWND hDlg, UINT umsg, WPARAM wParam, LPARAM lPar return !0; case WM_DPICHANGED: - UpdateWindowLayoutForDPI(hDlg, (RECT*)lParam, NULL); + UpdateWindowLayoutForDPI(hDlg, (RECT*)lParam, 0); return !0; #ifdef D_NP3_WIN10_DARK_MODE