1 // Scintilla source code edit control
2 /** @file ViewStyle.cxx
3 ** Store information on how the document is to be viewed.
4 **/
5 // Copyright 1998-2003 by Neil Hodgson <[email protected]>
6 // The License.txt file describes the conditions under which this software may be distributed.
7
8 #include <cstddef>
9 #include <cassert>
10 #include <cstring>
11
12 #include <stdexcept>
13 #include <string_view>
14 #include <vector>
15 #include <map>
16 #include <algorithm>
17 #include <memory>
18
19 #include "Platform.h"
20
21 #include "Scintilla.h"
22 #include "Position.h"
23 #include "UniqueString.h"
24 #include "Indicator.h"
25 #include "XPM.h"
26 #include "LineMarker.h"
27 #include "Style.h"
28 #include "ViewStyle.h"
29
30 using namespace Scintilla;
31
MarginStyle(int style_,int width_,int mask_)32 MarginStyle::MarginStyle(int style_, int width_, int mask_) noexcept :
33 style(style_), width(width_), mask(mask_), sensitive(false), cursor(SC_CURSORREVERSEARROW) {
34 }
35
36 FontRealised::FontRealised() noexcept = default;
37
~FontRealised()38 FontRealised::~FontRealised() {
39 font.Release();
40 }
41
Realise(Surface & surface,int zoomLevel,int technology,const FontSpecification & fs)42 void FontRealised::Realise(Surface &surface, int zoomLevel, int technology, const FontSpecification &fs) {
43 PLATFORM_ASSERT(fs.fontName);
44 sizeZoomed = fs.size + zoomLevel * SC_FONT_SIZE_MULTIPLIER;
45 if (sizeZoomed <= 2 * SC_FONT_SIZE_MULTIPLIER) // Hangs if sizeZoomed <= 1
46 sizeZoomed = 2 * SC_FONT_SIZE_MULTIPLIER;
47
48 const float deviceHeight = static_cast<float>(surface.DeviceHeightFont(sizeZoomed));
49 const FontParameters fp(fs.fontName, deviceHeight / SC_FONT_SIZE_MULTIPLIER, fs.weight, fs.italic, fs.extraFontFlag, technology, fs.characterSet);
50 font.Create(fp);
51
52 ascent = static_cast<unsigned int>(surface.Ascent(font));
53 descent = static_cast<unsigned int>(surface.Descent(font));
54 capitalHeight = surface.Ascent(font) - surface.InternalLeading(font);
55 aveCharWidth = surface.AverageCharWidth(font);
56 spaceWidth = surface.WidthText(font, " ");
57 }
58
ViewStyle()59 ViewStyle::ViewStyle() : markers(MARKER_MAX + 1), indicators(INDICATOR_MAX + 1) {
60 Init();
61 }
62
63 // Copy constructor only called when printing copies the screen ViewStyle so it can be
64 // modified for printing styles.
ViewStyle(const ViewStyle & source)65 ViewStyle::ViewStyle(const ViewStyle &source) : markers(MARKER_MAX + 1), indicators(INDICATOR_MAX + 1) {
66 Init(source.styles.size());
67 styles = source.styles;
68 for (size_t sty=0; sty<source.styles.size(); sty++) {
69 // Can't just copy fontName as its lifetime is relative to its owning ViewStyle
70 styles[sty].fontName = fontNames.Save(source.styles[sty].fontName);
71 }
72 nextExtendedStyle = source.nextExtendedStyle;
73 markers = source.markers;
74 CalcLargestMarkerHeight();
75
76 indicators = source.indicators;
77
78 indicatorsDynamic = source.indicatorsDynamic;
79 indicatorsSetFore = source.indicatorsSetFore;
80
81 selColours = source.selColours;
82 selAdditionalForeground = source.selAdditionalForeground;
83 selAdditionalBackground = source.selAdditionalBackground;
84 selBackground2 = source.selBackground2;
85 selAlpha = source.selAlpha;
86 selAdditionalAlpha = source.selAdditionalAlpha;
87 selEOLFilled = source.selEOLFilled;
88
89 foldmarginColour = source.foldmarginColour;
90 foldmarginHighlightColour = source.foldmarginHighlightColour;
91
92 hotspotColours = source.hotspotColours;
93 hotspotUnderline = source.hotspotUnderline;
94 hotspotSingleLine = source.hotspotSingleLine;
95
96 whitespaceColours = source.whitespaceColours;
97 controlCharSymbol = source.controlCharSymbol;
98 controlCharWidth = source.controlCharWidth;
99 selbar = source.selbar;
100 selbarlight = source.selbarlight;
101 caretcolour = source.caretcolour;
102 additionalCaretColour = source.additionalCaretColour;
103 caretLineFrame = source.caretLineFrame;
104 showCaretLineBackground = source.showCaretLineBackground;
105 alwaysShowCaretLineBackground = source.alwaysShowCaretLineBackground;
106 caretLineBackground = source.caretLineBackground;
107 caretLineAlpha = source.caretLineAlpha;
108 caretStyle = source.caretStyle;
109 caretWidth = source.caretWidth;
110 someStylesProtected = false;
111 someStylesForceCase = false;
112 leftMarginWidth = source.leftMarginWidth;
113 rightMarginWidth = source.rightMarginWidth;
114 ms = source.ms;
115 maskInLine = source.maskInLine;
116 maskDrawInText = source.maskDrawInText;
117 fixedColumnWidth = source.fixedColumnWidth;
118 marginInside = source.marginInside;
119 textStart = source.textStart;
120 zoomLevel = source.zoomLevel;
121 viewWhitespace = source.viewWhitespace;
122 tabDrawMode = source.tabDrawMode;
123 whitespaceSize = source.whitespaceSize;
124 viewIndentationGuides = source.viewIndentationGuides;
125 viewEOL = source.viewEOL;
126 extraFontFlag = source.extraFontFlag;
127 extraAscent = source.extraAscent;
128 extraDescent = source.extraDescent;
129 marginStyleOffset = source.marginStyleOffset;
130 annotationVisible = source.annotationVisible;
131 annotationStyleOffset = source.annotationStyleOffset;
132 eolAnnotationVisible = source.eolAnnotationVisible;
133 eolAnnotationStyleOffset = source.eolAnnotationStyleOffset;
134 braceHighlightIndicatorSet = source.braceHighlightIndicatorSet;
135 braceHighlightIndicator = source.braceHighlightIndicator;
136 braceBadLightIndicatorSet = source.braceBadLightIndicatorSet;
137 braceBadLightIndicator = source.braceBadLightIndicator;
138
139 edgeState = source.edgeState;
140 theEdge = source.theEdge;
141 theMultiEdge = source.theMultiEdge;
142
143 marginNumberPadding = source.marginNumberPadding;
144 ctrlCharPadding = source.ctrlCharPadding;
145 lastSegItalicsOffset = source.lastSegItalicsOffset;
146
147 wrapState = source.wrapState;
148 wrapVisualFlags = source.wrapVisualFlags;
149 wrapVisualFlagsLocation = source.wrapVisualFlagsLocation;
150 wrapVisualStartIndent = source.wrapVisualStartIndent;
151 wrapIndentMode = source.wrapIndentMode;
152 }
153
~ViewStyle()154 ViewStyle::~ViewStyle() {
155 styles.clear();
156 fonts.clear();
157 }
158
CalculateMarginWidthAndMask()159 void ViewStyle::CalculateMarginWidthAndMask() noexcept {
160 fixedColumnWidth = marginInside ? leftMarginWidth : 0;
161 maskInLine = 0xffffffff;
162 int maskDefinedMarkers = 0;
163 for (const MarginStyle &m : ms) {
164 fixedColumnWidth += m.width;
165 if (m.width > 0)
166 maskInLine &= ~m.mask;
167 maskDefinedMarkers |= m.mask;
168 }
169 maskDrawInText = 0;
170 for (int markBit = 0; markBit < 32; markBit++) {
171 const int maskBit = 1U << markBit;
172 switch (markers[markBit].markType) {
173 case SC_MARK_EMPTY:
174 maskInLine &= ~maskBit;
175 break;
176 case SC_MARK_BACKGROUND:
177 case SC_MARK_UNDERLINE:
178 maskInLine &= ~maskBit;
179 maskDrawInText |= maskDefinedMarkers & maskBit;
180 break;
181 }
182 }
183 }
184
Init(size_t stylesSize_)185 void ViewStyle::Init(size_t stylesSize_) {
186 AllocStyles(stylesSize_);
187 nextExtendedStyle = 256;
188 fontNames.Clear();
189 ResetDefaultStyle();
190
191 // There are no image markers by default, so no need for calling CalcLargestMarkerHeight()
192 largestMarkerHeight = 0;
193
194 indicators[0] = Indicator(INDIC_SQUIGGLE, ColourDesired(0, 0x7f, 0));
195 indicators[1] = Indicator(INDIC_TT, ColourDesired(0, 0, 0xff));
196 indicators[2] = Indicator(INDIC_PLAIN, ColourDesired(0xff, 0, 0));
197
198 technology = SC_TECHNOLOGY_DEFAULT;
199 indicatorsDynamic = false;
200 indicatorsSetFore = false;
201 lineHeight = 1;
202 lineOverlap = 0;
203 maxAscent = 1;
204 maxDescent = 1;
205 aveCharWidth = 8;
206 spaceWidth = 8;
207 tabWidth = spaceWidth * 8;
208
209 selColours.fore = ColourOptional(ColourDesired(0xff, 0, 0));
210 selColours.back = ColourOptional(ColourDesired(0xc0, 0xc0, 0xc0), true);
211 selAdditionalForeground = ColourDesired(0xff, 0, 0);
212 selAdditionalBackground = ColourDesired(0xd7, 0xd7, 0xd7);
213 selBackground2 = ColourDesired(0xb0, 0xb0, 0xb0);
214 selAlpha = SC_ALPHA_NOALPHA;
215 selAdditionalAlpha = SC_ALPHA_NOALPHA;
216 selEOLFilled = false;
217
218 foldmarginColour = ColourOptional(ColourDesired(0xff, 0, 0));
219 foldmarginHighlightColour = ColourOptional(ColourDesired(0xc0, 0xc0, 0xc0));
220
221 whitespaceColours.fore = ColourOptional();
222 whitespaceColours.back = ColourOptional(ColourDesired(0xff, 0xff, 0xff));
223 controlCharSymbol = 0; /* Draw the control characters */
224 controlCharWidth = 0;
225 selbar = Platform::Chrome();
226 selbarlight = Platform::ChromeHighlight();
227 styles[STYLE_LINENUMBER].fore = ColourDesired(0, 0, 0);
228 styles[STYLE_LINENUMBER].back = Platform::Chrome();
229 caretcolour = ColourDesired(0, 0, 0);
230 additionalCaretColour = ColourDesired(0x7f, 0x7f, 0x7f);
231 caretLineFrame = 0;
232 showCaretLineBackground = false;
233 alwaysShowCaretLineBackground = false;
234 caretLineBackground = ColourDesired(0xff, 0xff, 0);
235 caretLineAlpha = SC_ALPHA_NOALPHA;
236 caretStyle = CARETSTYLE_LINE;
237 caretWidth = 1;
238 someStylesProtected = false;
239 someStylesForceCase = false;
240
241 hotspotColours.fore = ColourOptional(ColourDesired(0, 0, 0xff));
242 hotspotColours.back = ColourOptional(ColourDesired(0xff, 0xff, 0xff));
243 hotspotUnderline = true;
244 hotspotSingleLine = true;
245
246 leftMarginWidth = 1;
247 rightMarginWidth = 1;
248 ms.resize(SC_MAX_MARGIN + 1);
249 ms[0] = MarginStyle(SC_MARGIN_NUMBER);
250 ms[1] = MarginStyle(SC_MARGIN_SYMBOL, 16, ~SC_MASK_FOLDERS);
251 ms[2] = MarginStyle(SC_MARGIN_SYMBOL);
252 marginInside = true;
253 CalculateMarginWidthAndMask();
254 textStart = marginInside ? fixedColumnWidth : leftMarginWidth;
255 zoomLevel = 0;
256 viewWhitespace = wsInvisible;
257 tabDrawMode = tdLongArrow;
258 whitespaceSize = 1;
259 viewIndentationGuides = ivNone;
260 viewEOL = false;
261 extraFontFlag = 0;
262 extraAscent = 0;
263 extraDescent = 0;
264 marginStyleOffset = 0;
265 annotationVisible = ANNOTATION_HIDDEN;
266 annotationStyleOffset = 0;
267 eolAnnotationVisible = EOLANNOTATION_HIDDEN;
268 eolAnnotationStyleOffset = 0;
269 braceHighlightIndicatorSet = false;
270 braceHighlightIndicator = 0;
271 braceBadLightIndicatorSet = false;
272 braceBadLightIndicator = 0;
273
274 edgeState = EDGE_NONE;
275 theEdge = EdgeProperties(0, ColourDesired(0xc0, 0xc0, 0xc0));
276
277 marginNumberPadding = 3;
278 ctrlCharPadding = 3; // +3 For a blank on front and rounded edge each side
279 lastSegItalicsOffset = 2;
280
281 wrapState = WrapMode::none;
282 wrapVisualFlags = 0;
283 wrapVisualFlagsLocation = 0;
284 wrapVisualStartIndent = 0;
285 wrapIndentMode = SC_WRAPINDENT_FIXED;
286 }
287
Refresh(Surface & surface,int tabInChars)288 void ViewStyle::Refresh(Surface &surface, int tabInChars) {
289 fonts.clear();
290
291 selbar = Platform::Chrome();
292 selbarlight = Platform::ChromeHighlight();
293
294 // Apply the extra font flag which controls text drawing quality to each style.
295 for (Style &style : styles) {
296 style.extraFontFlag = extraFontFlag;
297 }
298
299 // Create a FontRealised object for each unique font in the styles.
300 CreateAndAddFont(styles[STYLE_DEFAULT]);
301 for (const Style &style : styles) {
302 CreateAndAddFont(style);
303 }
304
305 // Ask platform to allocate each unique font.
306 for (std::pair<const FontSpecification, std::unique_ptr<FontRealised>> &font : fonts) {
307 font.second->Realise(surface, zoomLevel, technology, font.first);
308 }
309
310 // Set the platform font handle and measurements for each style.
311 for (Style &style : styles) {
312 FontRealised *fr = Find(style);
313 style.Copy(fr->font, *fr);
314 }
315
316 indicatorsDynamic = std::any_of(indicators.cbegin(), indicators.cend(),
317 [](const Indicator &indicator) noexcept { return indicator.IsDynamic(); });
318
319 indicatorsSetFore = std::any_of(indicators.cbegin(), indicators.cend(),
320 [](const Indicator &indicator) noexcept { return indicator.OverridesTextFore(); });
321
322 maxAscent = 1;
323 maxDescent = 1;
324 FindMaxAscentDescent();
325 maxAscent += extraAscent;
326 maxDescent += extraDescent;
327 lineHeight = maxAscent + maxDescent;
328 lineOverlap = lineHeight / 10;
329 if (lineOverlap < 2)
330 lineOverlap = 2;
331 if (lineOverlap > lineHeight)
332 lineOverlap = lineHeight;
333
334 someStylesProtected = std::any_of(styles.cbegin(), styles.cend(),
335 [](const Style &style) noexcept { return style.IsProtected(); });
336
337 someStylesForceCase = std::any_of(styles.cbegin(), styles.cend(),
338 [](const Style &style) noexcept { return style.caseForce != Style::caseMixed; });
339
340 aveCharWidth = styles[STYLE_DEFAULT].aveCharWidth;
341 spaceWidth = styles[STYLE_DEFAULT].spaceWidth;
342 tabWidth = spaceWidth * tabInChars;
343
344 controlCharWidth = 0.0;
345 if (controlCharSymbol >= 32) {
346 const char cc[2] = { static_cast<char>(controlCharSymbol), '\0' };
347 controlCharWidth = surface.WidthText(styles[STYLE_CONTROLCHAR].font, cc);
348 }
349
350 CalculateMarginWidthAndMask();
351 textStart = marginInside ? fixedColumnWidth : leftMarginWidth;
352 }
353
ReleaseAllExtendedStyles()354 void ViewStyle::ReleaseAllExtendedStyles() noexcept {
355 nextExtendedStyle = 256;
356 }
357
AllocateExtendedStyles(int numberStyles)358 int ViewStyle::AllocateExtendedStyles(int numberStyles) {
359 const int startRange = nextExtendedStyle;
360 nextExtendedStyle += numberStyles;
361 EnsureStyle(nextExtendedStyle);
362 for (int i=startRange; i<nextExtendedStyle; i++) {
363 styles[i].ClearTo(styles[STYLE_DEFAULT]);
364 }
365 return startRange;
366 }
367
EnsureStyle(size_t index)368 void ViewStyle::EnsureStyle(size_t index) {
369 if (index >= styles.size()) {
370 AllocStyles(index+1);
371 }
372 }
373
ResetDefaultStyle()374 void ViewStyle::ResetDefaultStyle() {
375 styles[STYLE_DEFAULT].Clear(ColourDesired(0,0,0),
376 ColourDesired(0xff,0xff,0xff),
377 Platform::DefaultFontSize() * SC_FONT_SIZE_MULTIPLIER, fontNames.Save(Platform::DefaultFont()),
378 SC_CHARSET_DEFAULT,
379 SC_WEIGHT_NORMAL, false, false, false, Style::caseMixed, true, true, false);
380 }
381
ClearStyles()382 void ViewStyle::ClearStyles() {
383 // Reset all styles to be like the default style
384 for (size_t i=0; i<styles.size(); i++) {
385 if (i != STYLE_DEFAULT) {
386 styles[i].ClearTo(styles[STYLE_DEFAULT]);
387 }
388 }
389 styles[STYLE_LINENUMBER].back = Platform::Chrome();
390
391 // Set call tip fore/back to match the values previously set for call tips
392 styles[STYLE_CALLTIP].back = ColourDesired(0xff, 0xff, 0xff);
393 styles[STYLE_CALLTIP].fore = ColourDesired(0x80, 0x80, 0x80);
394 }
395
SetStyleFontName(int styleIndex,const char * name)396 void ViewStyle::SetStyleFontName(int styleIndex, const char *name) {
397 styles[styleIndex].fontName = fontNames.Save(name);
398 }
399
ProtectionActive() const400 bool ViewStyle::ProtectionActive() const noexcept {
401 return someStylesProtected;
402 }
403
ExternalMarginWidth() const404 int ViewStyle::ExternalMarginWidth() const noexcept {
405 return marginInside ? 0 : fixedColumnWidth;
406 }
407
MarginFromLocation(Point pt) const408 int ViewStyle::MarginFromLocation(Point pt) const noexcept {
409 int margin = -1;
410 int x = marginInside ? 0 : -fixedColumnWidth;
411 for (size_t i = 0; i < ms.size(); i++) {
412 if ((pt.x >= x) && (pt.x < x + ms[i].width))
413 margin = static_cast<int>(i);
414 x += ms[i].width;
415 }
416 return margin;
417 }
418
ValidStyle(size_t styleIndex) const419 bool ViewStyle::ValidStyle(size_t styleIndex) const noexcept {
420 return styleIndex < styles.size();
421 }
422
CalcLargestMarkerHeight()423 void ViewStyle::CalcLargestMarkerHeight() noexcept {
424 largestMarkerHeight = 0;
425 for (const LineMarker &marker : markers) {
426 switch (marker.markType) {
427 case SC_MARK_PIXMAP:
428 if (marker.pxpm && marker.pxpm->GetHeight() > largestMarkerHeight)
429 largestMarkerHeight = marker.pxpm->GetHeight();
430 break;
431 case SC_MARK_RGBAIMAGE:
432 if (marker.image && marker.image->GetHeight() > largestMarkerHeight)
433 largestMarkerHeight = marker.image->GetHeight();
434 break;
435 }
436 }
437 }
438
GetFrameWidth() const439 int ViewStyle::GetFrameWidth() const noexcept {
440 return std::clamp(caretLineFrame, 1, lineHeight / 3);
441 }
442
IsLineFrameOpaque(bool caretActive,bool lineContainsCaret) const443 bool ViewStyle::IsLineFrameOpaque(bool caretActive, bool lineContainsCaret) const noexcept {
444 return caretLineFrame && (caretActive || alwaysShowCaretLineBackground) && showCaretLineBackground &&
445 (caretLineAlpha == SC_ALPHA_NOALPHA) && lineContainsCaret;
446 }
447
448 // See if something overrides the line background colour: Either if caret is on the line
449 // and background colour is set for that, or if a marker is defined that forces its background
450 // colour onto the line, or if a marker is defined but has no selection margin in which to
451 // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
452 // with the earlier taking precedence. When multiple markers cause background override,
453 // the colour for the highest numbered one is used.
Background(int marksOfLine,bool caretActive,bool lineContainsCaret) const454 ColourOptional ViewStyle::Background(int marksOfLine, bool caretActive, bool lineContainsCaret) const noexcept {
455 ColourOptional background;
456 if (!caretLineFrame && (caretActive || alwaysShowCaretLineBackground) && showCaretLineBackground &&
457 (caretLineAlpha == SC_ALPHA_NOALPHA) && lineContainsCaret) {
458 background = ColourOptional(caretLineBackground, true);
459 }
460 if (!background.isSet && marksOfLine) {
461 int marks = marksOfLine;
462 for (int markBit = 0; (markBit < 32) && marks; markBit++) {
463 if ((marks & 1) && (markers[markBit].markType == SC_MARK_BACKGROUND) &&
464 (markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
465 background = ColourOptional(markers[markBit].back, true);
466 }
467 marks >>= 1;
468 }
469 }
470 if (!background.isSet && maskInLine) {
471 int marksMasked = marksOfLine & maskInLine;
472 if (marksMasked) {
473 for (int markBit = 0; (markBit < 32) && marksMasked; markBit++) {
474 if ((marksMasked & 1) &&
475 (markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
476 background = ColourOptional(markers[markBit].back, true);
477 }
478 marksMasked >>= 1;
479 }
480 }
481 }
482 return background;
483 }
484
SelectionBackgroundDrawn() const485 bool ViewStyle::SelectionBackgroundDrawn() const noexcept {
486 return selColours.back.isSet &&
487 ((selAlpha == SC_ALPHA_NOALPHA) || (selAdditionalAlpha == SC_ALPHA_NOALPHA));
488 }
489
WhitespaceBackgroundDrawn() const490 bool ViewStyle::WhitespaceBackgroundDrawn() const noexcept {
491 return (viewWhitespace != wsInvisible) && (whitespaceColours.back.isSet);
492 }
493
WhiteSpaceVisible(bool inIndent) const494 bool ViewStyle::WhiteSpaceVisible(bool inIndent) const noexcept {
495 return (!inIndent && viewWhitespace == wsVisibleAfterIndent) ||
496 (inIndent && viewWhitespace == wsVisibleOnlyInIndent) ||
497 viewWhitespace == wsVisibleAlways;
498 }
499
WrapColour() const500 ColourDesired ViewStyle::WrapColour() const noexcept {
501 if (whitespaceColours.fore.isSet)
502 return whitespaceColours.fore;
503 else
504 return styles[STYLE_DEFAULT].fore;
505 }
506
507 // Insert new edge in sorted order.
AddMultiEdge(uptr_t wParam,sptr_t lParam)508 void ViewStyle::AddMultiEdge(uptr_t wParam, sptr_t lParam) {
509 const int column = static_cast<int>(wParam);
510 theMultiEdge.insert(
511 std::upper_bound(theMultiEdge.begin(), theMultiEdge.end(), column,
512 [](const EdgeProperties &a, const EdgeProperties &b) {
513 return a.column < b.column;
514 }),
515 EdgeProperties(column, lParam));
516 }
517
SetWrapState(int wrapState_)518 bool ViewStyle::SetWrapState(int wrapState_) noexcept {
519 WrapMode wrapStateWanted;
520 switch (wrapState_) {
521 case SC_WRAP_WORD:
522 wrapStateWanted = WrapMode::word;
523 break;
524 case SC_WRAP_CHAR:
525 wrapStateWanted = WrapMode::character;
526 break;
527 case SC_WRAP_WHITESPACE:
528 wrapStateWanted = WrapMode::whitespace;
529 break;
530 default:
531 wrapStateWanted = WrapMode::none;
532 break;
533 }
534 const bool changed = wrapState != wrapStateWanted;
535 wrapState = wrapStateWanted;
536 return changed;
537 }
538
SetWrapVisualFlags(int wrapVisualFlags_)539 bool ViewStyle::SetWrapVisualFlags(int wrapVisualFlags_) noexcept {
540 const bool changed = wrapVisualFlags != wrapVisualFlags_;
541 wrapVisualFlags = wrapVisualFlags_;
542 return changed;
543 }
544
SetWrapVisualFlagsLocation(int wrapVisualFlagsLocation_)545 bool ViewStyle::SetWrapVisualFlagsLocation(int wrapVisualFlagsLocation_) noexcept {
546 const bool changed = wrapVisualFlagsLocation != wrapVisualFlagsLocation_;
547 wrapVisualFlagsLocation = wrapVisualFlagsLocation_;
548 return changed;
549 }
550
SetWrapVisualStartIndent(int wrapVisualStartIndent_)551 bool ViewStyle::SetWrapVisualStartIndent(int wrapVisualStartIndent_) noexcept {
552 const bool changed = wrapVisualStartIndent != wrapVisualStartIndent_;
553 wrapVisualStartIndent = wrapVisualStartIndent_;
554 return changed;
555 }
556
SetWrapIndentMode(int wrapIndentMode_)557 bool ViewStyle::SetWrapIndentMode(int wrapIndentMode_) noexcept {
558 const bool changed = wrapIndentMode != wrapIndentMode_;
559 wrapIndentMode = wrapIndentMode_;
560 return changed;
561 }
562
IsBlockCaretStyle() const563 bool ViewStyle::IsBlockCaretStyle() const noexcept {
564 return ((caretStyle & CARETSTYLE_INS_MASK) == CARETSTYLE_BLOCK) ||
565 (caretStyle & CARETSTYLE_OVERSTRIKE_BLOCK) != 0;
566 }
567
IsCaretVisible() const568 bool ViewStyle::IsCaretVisible() const noexcept {
569 return caretWidth > 0 && caretStyle != CARETSTYLE_INVISIBLE;
570 }
571
DrawCaretInsideSelection(bool inOverstrike,bool imeCaretBlockOverride) const572 bool ViewStyle::DrawCaretInsideSelection(bool inOverstrike, bool imeCaretBlockOverride) const noexcept {
573 if (caretStyle & CARETSTYLE_BLOCK_AFTER)
574 return false;
575 return ((caretStyle & CARETSTYLE_INS_MASK) == CARETSTYLE_BLOCK) ||
576 (inOverstrike && (caretStyle & CARETSTYLE_OVERSTRIKE_BLOCK) != 0) ||
577 imeCaretBlockOverride;
578 }
579
CaretShapeForMode(bool inOverstrike) const580 ViewStyle::CaretShape ViewStyle::CaretShapeForMode(bool inOverstrike) const noexcept {
581 if (inOverstrike) {
582 return (caretStyle & CARETSTYLE_OVERSTRIKE_BLOCK) ? CaretShape::block : CaretShape::bar;
583 }
584
585 const int caret = caretStyle & CARETSTYLE_INS_MASK;
586 return (caret <= CARETSTYLE_BLOCK) ? static_cast<CaretShape>(caret) : CaretShape::line;
587 }
588
AllocStyles(size_t sizeNew)589 void ViewStyle::AllocStyles(size_t sizeNew) {
590 size_t i=styles.size();
591 styles.resize(sizeNew);
592 if (styles.size() > STYLE_DEFAULT) {
593 for (; i<sizeNew; i++) {
594 if (i != STYLE_DEFAULT) {
595 styles[i].ClearTo(styles[STYLE_DEFAULT]);
596 }
597 }
598 }
599 }
600
CreateAndAddFont(const FontSpecification & fs)601 void ViewStyle::CreateAndAddFont(const FontSpecification &fs) {
602 if (fs.fontName) {
603 FontMap::iterator it = fonts.find(fs);
604 if (it == fonts.end()) {
605 fonts[fs] = std::make_unique<FontRealised>();
606 }
607 }
608 }
609
Find(const FontSpecification & fs)610 FontRealised *ViewStyle::Find(const FontSpecification &fs) {
611 if (!fs.fontName) // Invalid specification so return arbitrary object
612 return fonts.begin()->second.get();
613 FontMap::iterator it = fonts.find(fs);
614 if (it != fonts.end()) {
615 // Should always reach here since map was just set for all styles
616 return it->second.get();
617 }
618 return nullptr;
619 }
620
FindMaxAscentDescent()621 void ViewStyle::FindMaxAscentDescent() {
622 for (FontMap::const_iterator it = fonts.cbegin(); it != fonts.cend(); ++it) {
623 if (maxAscent < it->second->ascent)
624 maxAscent = it->second->ascent;
625 if (maxDescent < it->second->descent)
626 maxDescent = it->second->descent;
627 }
628 }
629