From 4d1a31d6a74019c3d43de1c33e2be093ed6dfd11 Mon Sep 17 00:00:00 2001 From: Neil Date: Sat, 31 Jul 2021 08:49:25 +1000 Subject: Implement StyleSetCheckMonospaced. --- src/Editor.cxx | 9 ++++++++- src/PositionCache.cxx | 16 ++++++++++++++++ src/Style.cxx | 1 + src/Style.h | 2 ++ src/ViewStyle.cxx | 19 +++++++++++++++++++ 5 files changed, 46 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/Editor.cxx b/src/Editor.cxx index db7e2366e..bd2742539 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -117,7 +117,7 @@ static constexpr bool IsAllSpacesOrTabs(std::string_view sv) noexcept { return true; } -Editor::Editor() : durationWrapOneByte(0.000001, 0.0000001, 0.00001) { +Editor::Editor() : durationWrapOneByte(0.000001, 0.00000001, 0.00001) { ctrlID = 0; stylesValid = false; @@ -5748,6 +5748,9 @@ void Editor::StyleSetMessage(Message iMessage, uptr_t wParam, sptr_t lParam) { case Message::StyleSetHotSpot: vs.styles[wParam].hotspot = lParam != 0; break; + case Message::StyleSetCheckMonospaced: + vs.styles[wParam].checkMonospaced = lParam != 0; + break; default: break; } @@ -5787,6 +5790,8 @@ sptr_t Editor::StyleGetMessage(Message iMessage, uptr_t wParam, sptr_t lParam) { return vs.styles[wParam].changeable ? 1 : 0; case Message::StyleGetHotSpot: return vs.styles[wParam].hotspot ? 1 : 0; + case Message::StyleGetCheckMonospaced: + return vs.styles[wParam].checkMonospaced ? 1 : 0; default: break; } @@ -7202,6 +7207,7 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) { case Message::StyleSetVisible: case Message::StyleSetChangeable: case Message::StyleSetHotSpot: + case Message::StyleSetCheckMonospaced: StyleSetMessage(iMessage, wParam, lParam); break; @@ -7220,6 +7226,7 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) { case Message::StyleGetVisible: case Message::StyleGetChangeable: case Message::StyleGetHotSpot: + case Message::StyleGetCheckMonospaced: return StyleGetMessage(iMessage, wParam, lParam); case Message::StyleResetDefault: diff --git a/src/PositionCache.cxx b/src/PositionCache.cxx index 714937dc1..fda736cc7 100644 --- a/src/PositionCache.cxx +++ b/src/PositionCache.cxx @@ -377,6 +377,14 @@ constexpr size_t AlignUp(size_t value, size_t alignment) noexcept { constexpr size_t alignmentLLC = 20; +constexpr bool GraphicASCII(char ch) noexcept { + return ch >= ' ' && ch <= '~'; +} + +bool AllGraphicASCII(std::string_view text) noexcept { + return std::all_of(text.cbegin(), text.cend(), GraphicASCII); +} + } @@ -895,6 +903,14 @@ void PositionCache::MeasureWidths(Surface *surface, const ViewStyle &vstyle, uns probe = probe2; } } + if (vstyle.styles[styleNumber].monospaceASCII) { + if (AllGraphicASCII(sv)) { + for (size_t i = 0; i < sv.length(); i++) { + positions[i] = vstyle.styles[styleNumber].aveCharWidth * (i+1); + } + return; + } + } const Font *fontStyle = vstyle.styles[styleNumber].font.get(); surface->MeasureWidths(fontStyle, sv, positions); if (probe < pces.size()) { diff --git a/src/Style.cxx b/src/Style.cxx index d71b62d97..3a57d1a08 100644 --- a/src/Style.cxx +++ b/src/Style.cxx @@ -57,6 +57,7 @@ void FontMeasurements::ClearMeasurements() noexcept { capitalHeight = 1; aveCharWidth = 1; spaceWidth = 1; + monospaceASCII = false; sizeZoomed = 2; } diff --git a/src/Style.h b/src/Style.h index 8153d156e..087b13b2f 100644 --- a/src/Style.h +++ b/src/Style.h @@ -17,6 +17,7 @@ struct FontSpecification { int size; Scintilla::CharacterSet characterSet; Scintilla::FontQuality extraFontFlag; + bool checkMonospaced = false; FontSpecification() noexcept : fontName(nullptr), weight(Scintilla::FontWeight::Normal), @@ -35,6 +36,7 @@ struct FontMeasurements { XYPOSITION capitalHeight; // Top of capital letter to baseline: ascent - internal leading XYPOSITION aveCharWidth; XYPOSITION spaceWidth; + bool monospaceASCII = false; int sizeZoomed; FontMeasurements() noexcept; void ClearMeasurements() noexcept; diff --git a/src/ViewStyle.cxx b/src/ViewStyle.cxx index 33b861445..47f76d357 100644 --- a/src/ViewStyle.cxx +++ b/src/ViewStyle.cxx @@ -18,6 +18,7 @@ #include #include #include +#include #include "ScintillaTypes.h" @@ -64,6 +65,24 @@ void FontRealised::Realise(Surface &surface, int zoomLevel, Technology technolog capitalHeight = surface.Ascent(font.get()) - surface.InternalLeading(font.get()); aveCharWidth = surface.AverageCharWidth(font.get()); spaceWidth = surface.WidthText(font.get(), " "); + + if (fs.checkMonospaced) { + std::string allASCIIGraphic("Ayfi"); // "Ay" is normally strongly kerned and "fi" may be a ligature + for (unsigned char ch = 0x20; ch <= 0x7E; ch++) { + allASCIIGraphic.push_back(ch); + } + std::vector positions(allASCIIGraphic.length()); + surface.MeasureWidths(font.get(), allASCIIGraphic, positions.data()); + std::adjacent_difference(positions.begin(), positions.end(), positions.begin()); + const XYPOSITION maxWidth = *std::max_element(positions.begin(), positions.end()); + const XYPOSITION minWidth = *std::min_element(positions.begin(), positions.end()); + const XYPOSITION variance = maxWidth - minWidth; + const XYPOSITION scaledVariance = variance / aveCharWidth; + constexpr XYPOSITION monospaceWidthEpsilon = 0.000001; // May need tweaking if monospace fonts vary more + monospaceASCII = scaledVariance < monospaceWidthEpsilon; + } else { + monospaceASCII = false; + } } ViewStyle::ViewStyle() : markers(MarkerMax + 1), indicators(static_cast(IndicatorNumbers::Max) + 1) { -- cgit v1.2.3