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 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 38 FontRealised::~FontRealised() { 39 font.Release(); 40 } 41 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 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. 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 154 ViewStyle::~ViewStyle() { 155 styles.clear(); 156 fonts.clear(); 157 } 158 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 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 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 354 void ViewStyle::ReleaseAllExtendedStyles() noexcept { 355 nextExtendedStyle = 256; 356 } 357 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 368 void ViewStyle::EnsureStyle(size_t index) { 369 if (index >= styles.size()) { 370 AllocStyles(index+1); 371 } 372 } 373 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 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 396 void ViewStyle::SetStyleFontName(int styleIndex, const char *name) { 397 styles[styleIndex].fontName = fontNames.Save(name); 398 } 399 400 bool ViewStyle::ProtectionActive() const noexcept { 401 return someStylesProtected; 402 } 403 404 int ViewStyle::ExternalMarginWidth() const noexcept { 405 return marginInside ? 0 : fixedColumnWidth; 406 } 407 408 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 419 bool ViewStyle::ValidStyle(size_t styleIndex) const noexcept { 420 return styleIndex < styles.size(); 421 } 422 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 439 int ViewStyle::GetFrameWidth() const noexcept { 440 return std::clamp(caretLineFrame, 1, lineHeight / 3); 441 } 442 443 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. 454 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 485 bool ViewStyle::SelectionBackgroundDrawn() const noexcept { 486 return selColours.back.isSet && 487 ((selAlpha == SC_ALPHA_NOALPHA) || (selAdditionalAlpha == SC_ALPHA_NOALPHA)); 488 } 489 490 bool ViewStyle::WhitespaceBackgroundDrawn() const noexcept { 491 return (viewWhitespace != wsInvisible) && (whitespaceColours.back.isSet); 492 } 493 494 bool ViewStyle::WhiteSpaceVisible(bool inIndent) const noexcept { 495 return (!inIndent && viewWhitespace == wsVisibleAfterIndent) || 496 (inIndent && viewWhitespace == wsVisibleOnlyInIndent) || 497 viewWhitespace == wsVisibleAlways; 498 } 499 500 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. 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 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 539 bool ViewStyle::SetWrapVisualFlags(int wrapVisualFlags_) noexcept { 540 const bool changed = wrapVisualFlags != wrapVisualFlags_; 541 wrapVisualFlags = wrapVisualFlags_; 542 return changed; 543 } 544 545 bool ViewStyle::SetWrapVisualFlagsLocation(int wrapVisualFlagsLocation_) noexcept { 546 const bool changed = wrapVisualFlagsLocation != wrapVisualFlagsLocation_; 547 wrapVisualFlagsLocation = wrapVisualFlagsLocation_; 548 return changed; 549 } 550 551 bool ViewStyle::SetWrapVisualStartIndent(int wrapVisualStartIndent_) noexcept { 552 const bool changed = wrapVisualStartIndent != wrapVisualStartIndent_; 553 wrapVisualStartIndent = wrapVisualStartIndent_; 554 return changed; 555 } 556 557 bool ViewStyle::SetWrapIndentMode(int wrapIndentMode_) noexcept { 558 const bool changed = wrapIndentMode != wrapIndentMode_; 559 wrapIndentMode = wrapIndentMode_; 560 return changed; 561 } 562 563 bool ViewStyle::IsBlockCaretStyle() const noexcept { 564 return ((caretStyle & CARETSTYLE_INS_MASK) == CARETSTYLE_BLOCK) || 565 (caretStyle & CARETSTYLE_OVERSTRIKE_BLOCK) != 0; 566 } 567 568 bool ViewStyle::IsCaretVisible() const noexcept { 569 return caretWidth > 0 && caretStyle != CARETSTYLE_INVISIBLE; 570 } 571 572 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 580 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 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 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 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 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