| 1 | // Scintilla source code edit control |
| 2 | /** @file PositionCache.h |
| 3 | ** Classes for caching layout information. |
| 4 | **/ |
| 5 | // Copyright 1998-2009 by Neil Hodgson <neilh@scintilla.org> |
| 6 | // The License.txt file describes the conditions under which this software may be distributed. |
| 7 | |
| 8 | #ifndef POSITIONCACHE_H |
| 9 | #define POSITIONCACHE_H |
| 10 | |
| 11 | namespace Scintilla::Internal { |
| 12 | |
| 13 | /** |
| 14 | * A point in document space. |
| 15 | * Uses double for sufficient resolution in large (>20,000,000 line) documents. |
| 16 | */ |
| 17 | class PointDocument { |
| 18 | public: |
| 19 | double x; |
| 20 | double y; |
| 21 | |
| 22 | explicit PointDocument(double x_ = 0, double y_ = 0) noexcept : x(x_), y(y_) { |
| 23 | } |
| 24 | |
| 25 | // Conversion from Point. |
| 26 | explicit PointDocument(Point pt) noexcept : x(pt.x), y(pt.y) { |
| 27 | } |
| 28 | }; |
| 29 | |
| 30 | // There are two points for some positions and this enumeration |
| 31 | // can choose between the end of the first line or subline |
| 32 | // and the start of the next line or subline. |
| 33 | enum class PointEnd { |
| 34 | start = 0x0, |
| 35 | lineEnd = 0x1, |
| 36 | subLineEnd = 0x2, |
| 37 | endEither = lineEnd | subLineEnd, |
| 38 | }; |
| 39 | |
| 40 | class BidiData { |
| 41 | public: |
| 42 | std::vector<std::shared_ptr<Font>> stylesFonts; |
| 43 | std::vector<XYPOSITION> widthReprs; |
| 44 | void Resize(size_t maxLineLength_); |
| 45 | }; |
| 46 | |
| 47 | /** |
| 48 | */ |
| 49 | class LineLayout { |
| 50 | private: |
| 51 | friend class LineLayoutCache; |
| 52 | std::unique_ptr<int []>lineStarts; |
| 53 | int lenLineStarts; |
| 54 | /// Drawing is only performed for @a maxLineLength characters on each line. |
| 55 | Sci::Line lineNumber; |
| 56 | public: |
| 57 | enum { wrapWidthInfinite = 0x7ffffff }; |
| 58 | |
| 59 | int maxLineLength; |
| 60 | int numCharsInLine; |
| 61 | int numCharsBeforeEOL; |
| 62 | enum class ValidLevel { invalid, checkTextAndStyle, positions, lines } validity; |
| 63 | int xHighlightGuide; |
| 64 | bool highlightColumn; |
| 65 | bool containsCaret; |
| 66 | int edgeColumn; |
| 67 | std::unique_ptr<char[]> chars; |
| 68 | std::unique_ptr<unsigned char[]> styles; |
| 69 | std::unique_ptr<XYPOSITION[]> positions; |
| 70 | char bracePreviousStyles[2]; |
| 71 | |
| 72 | std::unique_ptr<BidiData> bidiData; |
| 73 | |
| 74 | // Wrapped line support |
| 75 | int widthLine; |
| 76 | int lines; |
| 77 | XYPOSITION wrapIndent; // In pixels |
| 78 | |
| 79 | LineLayout(Sci::Line lineNumber_, int maxLineLength_); |
| 80 | // Deleted so LineLayout objects can not be copied. |
| 81 | LineLayout(const LineLayout &) = delete; |
| 82 | LineLayout(LineLayout &&) = delete; |
| 83 | void operator=(const LineLayout &) = delete; |
| 84 | void operator=(LineLayout &&) = delete; |
| 85 | virtual ~LineLayout(); |
| 86 | void Resize(int maxLineLength_); |
| 87 | void EnsureBidiData(); |
| 88 | void Free() noexcept; |
| 89 | void Invalidate(ValidLevel validity_) noexcept; |
| 90 | Sci::Line LineNumber() const noexcept; |
| 91 | bool CanHold(Sci::Line lineDoc, int lineLength_) const noexcept; |
| 92 | int LineStart(int line) const noexcept; |
| 93 | int LineLength(int line) const noexcept; |
| 94 | enum class Scope { visibleOnly, includeEnd }; |
| 95 | int LineLastVisible(int line, Scope scope) const noexcept; |
| 96 | Range SubLineRange(int subLine, Scope scope) const noexcept; |
| 97 | bool InLine(int offset, int line) const noexcept; |
| 98 | int SubLineFromPosition(int posInLine, PointEnd pe) const noexcept; |
| 99 | void SetLineStart(int line, int start); |
| 100 | void SetBracesHighlight(Range rangeLine, const Sci::Position braces[], |
| 101 | char bracesMatchStyle, int xHighlight, bool ignoreStyle); |
| 102 | void RestoreBracesHighlight(Range rangeLine, const Sci::Position braces[], bool ignoreStyle); |
| 103 | int FindBefore(XYPOSITION x, Range range) const noexcept; |
| 104 | int FindPositionFromX(XYPOSITION x, Range range, bool charPosition) const noexcept; |
| 105 | Point PointFromPosition(int posInLine, int lineHeight, PointEnd pe) const noexcept; |
| 106 | int EndLineStyle() const noexcept; |
| 107 | }; |
| 108 | |
| 109 | struct ScreenLine : public IScreenLine { |
| 110 | const LineLayout *ll; |
| 111 | size_t start; |
| 112 | size_t len; |
| 113 | XYPOSITION width; |
| 114 | XYPOSITION height; |
| 115 | int ctrlCharPadding; |
| 116 | XYPOSITION tabWidth; |
| 117 | int tabWidthMinimumPixels; |
| 118 | |
| 119 | ScreenLine(const LineLayout *ll_, int subLine, const ViewStyle &vs, XYPOSITION width_, int tabWidthMinimumPixels_); |
| 120 | // Deleted so ScreenLine objects can not be copied. |
| 121 | ScreenLine(const ScreenLine &) = delete; |
| 122 | ScreenLine(ScreenLine &&) = delete; |
| 123 | void operator=(const ScreenLine &) = delete; |
| 124 | void operator=(ScreenLine &&) = delete; |
| 125 | virtual ~ScreenLine(); |
| 126 | |
| 127 | std::string_view Text() const override; |
| 128 | size_t Length() const override; |
| 129 | size_t RepresentationCount() const override; |
| 130 | XYPOSITION Width() const override; |
| 131 | XYPOSITION Height() const override; |
| 132 | XYPOSITION TabWidth() const override; |
| 133 | XYPOSITION TabWidthMinimumPixels() const override; |
| 134 | const Font *FontOfPosition(size_t position) const override; |
| 135 | XYPOSITION RepresentationWidth(size_t position) const override; |
| 136 | XYPOSITION TabPositionAfter(XYPOSITION xPosition) const override; |
| 137 | }; |
| 138 | |
| 139 | /** |
| 140 | */ |
| 141 | class LineLayoutCache { |
| 142 | public: |
| 143 | private: |
| 144 | Scintilla::LineCache level; |
| 145 | std::vector<std::shared_ptr<LineLayout>>cache; |
| 146 | bool allInvalidated; |
| 147 | int styleClock; |
| 148 | size_t EntryForLine(Sci::Line line) const noexcept; |
| 149 | void AllocateForLevel(Sci::Line linesOnScreen, Sci::Line linesInDoc); |
| 150 | public: |
| 151 | LineLayoutCache(); |
| 152 | // Deleted so LineLayoutCache objects can not be copied. |
| 153 | LineLayoutCache(const LineLayoutCache &) = delete; |
| 154 | LineLayoutCache(LineLayoutCache &&) = delete; |
| 155 | void operator=(const LineLayoutCache &) = delete; |
| 156 | void operator=(LineLayoutCache &&) = delete; |
| 157 | virtual ~LineLayoutCache(); |
| 158 | void Deallocate() noexcept; |
| 159 | void Invalidate(LineLayout::ValidLevel validity_) noexcept; |
| 160 | void SetLevel(Scintilla::LineCache level_) noexcept; |
| 161 | Scintilla::LineCache GetLevel() const noexcept { return level; } |
| 162 | std::shared_ptr<LineLayout> Retrieve(Sci::Line lineNumber, Sci::Line lineCaret, int maxChars, int styleClock_, |
| 163 | Sci::Line linesOnScreen, Sci::Line linesInDoc); |
| 164 | }; |
| 165 | |
| 166 | class PositionCacheEntry { |
| 167 | uint16_t styleNumber; |
| 168 | uint16_t len; |
| 169 | uint16_t clock; |
| 170 | std::unique_ptr<XYPOSITION []> positions; |
| 171 | public: |
| 172 | PositionCacheEntry() noexcept; |
| 173 | // Copy constructor not currently used, but needed for being element in std::vector. |
| 174 | PositionCacheEntry(const PositionCacheEntry &); |
| 175 | PositionCacheEntry(PositionCacheEntry &&) noexcept = default; |
| 176 | // Deleted so PositionCacheEntry objects can not be assigned. |
| 177 | void operator=(const PositionCacheEntry &) = delete; |
| 178 | void operator=(PositionCacheEntry &&) = delete; |
| 179 | ~PositionCacheEntry(); |
| 180 | void Set(unsigned int styleNumber_, std::string_view sv, const XYPOSITION *positions_, uint16_t clock_); |
| 181 | void Clear() noexcept; |
| 182 | bool Retrieve(unsigned int styleNumber_, std::string_view sv, XYPOSITION *positions_) const noexcept; |
| 183 | static size_t Hash(unsigned int styleNumber_, std::string_view sv) noexcept; |
| 184 | bool NewerThan(const PositionCacheEntry &other) const noexcept; |
| 185 | void ResetClock() noexcept; |
| 186 | }; |
| 187 | |
| 188 | class Representation { |
| 189 | public: |
| 190 | static constexpr size_t maxLength = 200; |
| 191 | std::string stringRep; |
| 192 | RepresentationAppearance appearance; |
| 193 | ColourRGBA colour; |
| 194 | explicit Representation(std::string_view value="" , RepresentationAppearance appearance_= RepresentationAppearance::Blob) : |
| 195 | stringRep(value), appearance(appearance_) { |
| 196 | } |
| 197 | }; |
| 198 | |
| 199 | typedef std::map<unsigned int, Representation> MapRepresentation; |
| 200 | |
| 201 | class SpecialRepresentations { |
| 202 | MapRepresentation mapReprs; |
| 203 | unsigned short startByteHasReprs[0x100] {}; |
| 204 | unsigned int maxKey = 0; |
| 205 | bool crlf = false; |
| 206 | public: |
| 207 | void SetRepresentation(std::string_view charBytes, std::string_view value); |
| 208 | void SetRepresentationAppearance(std::string_view charBytes, RepresentationAppearance appearance); |
| 209 | void SetRepresentationColour(std::string_view charBytes, ColourRGBA colour); |
| 210 | void ClearRepresentation(std::string_view charBytes); |
| 211 | const Representation *GetRepresentation(std::string_view charBytes) const; |
| 212 | const Representation *RepresentationFromCharacter(std::string_view charBytes) const; |
| 213 | bool ContainsCrLf() const noexcept { |
| 214 | return crlf; |
| 215 | } |
| 216 | bool MayContain(unsigned char ch) const noexcept { |
| 217 | return startByteHasReprs[ch] != 0; |
| 218 | } |
| 219 | void Clear(); |
| 220 | }; |
| 221 | |
| 222 | struct TextSegment { |
| 223 | int start; |
| 224 | int length; |
| 225 | const Representation *representation; |
| 226 | TextSegment(int start_=0, int length_=0, const Representation *representation_=nullptr) noexcept : |
| 227 | start(start_), length(length_), representation(representation_) { |
| 228 | } |
| 229 | int end() const noexcept { |
| 230 | return start + length; |
| 231 | } |
| 232 | }; |
| 233 | |
| 234 | // Class to break a line of text into shorter runs at sensible places. |
| 235 | class BreakFinder { |
| 236 | const LineLayout *ll; |
| 237 | Range lineRange; |
| 238 | Sci::Position posLineStart; |
| 239 | int nextBreak; |
| 240 | std::vector<int> selAndEdge; |
| 241 | unsigned int saeCurrentPos; |
| 242 | int saeNext; |
| 243 | int subBreak; |
| 244 | const Document *pdoc; |
| 245 | const EncodingFamily encodingFamily; |
| 246 | const SpecialRepresentations *preprs; |
| 247 | void Insert(Sci::Position val); |
| 248 | public: |
| 249 | // If a whole run is longer than lengthStartSubdivision then subdivide |
| 250 | // into smaller runs at spaces or punctuation. |
| 251 | enum { lengthStartSubdivision = 300 }; |
| 252 | // Try to make each subdivided run lengthEachSubdivision or shorter. |
| 253 | enum { lengthEachSubdivision = 100 }; |
| 254 | enum class BreakFor { |
| 255 | Text = 0, |
| 256 | Selection = 1, |
| 257 | Foreground = 2, |
| 258 | ForegroundAndSelection = 3, |
| 259 | }; |
| 260 | BreakFinder(const LineLayout *ll_, const Selection *psel, Range lineRange_, Sci::Position posLineStart_, |
| 261 | XYPOSITION xStart, BreakFor breakFor, const Document *pdoc_, const SpecialRepresentations *preprs_, const ViewStyle *pvsDraw); |
| 262 | // Deleted so BreakFinder objects can not be copied. |
| 263 | BreakFinder(const BreakFinder &) = delete; |
| 264 | BreakFinder(BreakFinder &&) = delete; |
| 265 | void operator=(const BreakFinder &) = delete; |
| 266 | void operator=(BreakFinder &&) = delete; |
| 267 | ~BreakFinder() noexcept; |
| 268 | TextSegment Next(); |
| 269 | bool More() const noexcept; |
| 270 | }; |
| 271 | |
| 272 | class PositionCache { |
| 273 | std::vector<PositionCacheEntry> pces; |
| 274 | uint16_t clock; |
| 275 | bool allClear; |
| 276 | public: |
| 277 | PositionCache(); |
| 278 | void Clear() noexcept; |
| 279 | void SetSize(size_t size_); |
| 280 | size_t GetSize() const noexcept; |
| 281 | void MeasureWidths(Surface *surface, const ViewStyle &vstyle, unsigned int styleNumber, |
| 282 | std::string_view sv, XYPOSITION *positions); |
| 283 | }; |
| 284 | |
| 285 | } |
| 286 | |
| 287 | #endif |
| 288 | |