Update Scintilla to version 3.4.4
[TortoiseGit.git] / ext / scintilla / src / ViewStyle.cxx
blob59a13750e296b0b54381ea89129b12f11bfe1c89
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 <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
8 #include <string.h>
9 #include <assert.h>
11 #include <vector>
12 #include <map>
14 #include "Platform.h"
16 #include "Scintilla.h"
17 #include "SplitVector.h"
18 #include "Partitioning.h"
19 #include "RunStyles.h"
20 #include "Indicator.h"
21 #include "XPM.h"
22 #include "LineMarker.h"
23 #include "Style.h"
24 #include "ViewStyle.h"
26 #ifdef SCI_NAMESPACE
27 using namespace Scintilla;
28 #endif
30 MarginStyle::MarginStyle() :
31 style(SC_MARGIN_SYMBOL), width(0), mask(0), sensitive(false), cursor(SC_CURSORREVERSEARROW) {
34 // A list of the fontnames - avoids wasting space in each style
35 FontNames::FontNames() {
38 FontNames::~FontNames() {
39 Clear();
42 void FontNames::Clear() {
43 for (std::vector<char *>::const_iterator it=names.begin(); it != names.end(); ++it) {
44 delete []*it;
46 names.clear();
49 const char *FontNames::Save(const char *name) {
50 if (!name)
51 return 0;
53 for (std::vector<char *>::const_iterator it=names.begin(); it != names.end(); ++it) {
54 if (strcmp(*it, name) == 0) {
55 return *it;
58 const size_t lenName = strlen(name) + 1;
59 char *nameSave = new char[lenName];
60 memcpy(nameSave, name, lenName);
61 names.push_back(nameSave);
62 return nameSave;
65 FontRealised::FontRealised() {
68 FontRealised::~FontRealised() {
69 font.Release();
72 void FontRealised::Realise(Surface &surface, int zoomLevel, int technology, const FontSpecification &fs) {
73 PLATFORM_ASSERT(fs.fontName);
74 sizeZoomed = fs.size + zoomLevel * SC_FONT_SIZE_MULTIPLIER;
75 if (sizeZoomed <= 2 * SC_FONT_SIZE_MULTIPLIER) // Hangs if sizeZoomed <= 1
76 sizeZoomed = 2 * SC_FONT_SIZE_MULTIPLIER;
78 float deviceHeight = static_cast<float>(surface.DeviceHeightFont(sizeZoomed));
79 FontParameters fp(fs.fontName, deviceHeight / SC_FONT_SIZE_MULTIPLIER, fs.weight, fs.italic, fs.extraFontFlag, technology, fs.characterSet);
80 font.Create(fp);
82 ascent = static_cast<unsigned int>(surface.Ascent(font));
83 descent = static_cast<unsigned int>(surface.Descent(font));
84 aveCharWidth = surface.AverageCharWidth(font);
85 spaceWidth = surface.WidthChar(font, ' ');
88 ViewStyle::ViewStyle() {
89 Init();
92 ViewStyle::ViewStyle(const ViewStyle &source) {
93 Init(source.styles.size());
94 for (unsigned int sty=0; sty<source.styles.size(); sty++) {
95 styles[sty] = source.styles[sty];
96 // Can't just copy fontname as its lifetime is relative to its owning ViewStyle
97 styles[sty].fontName = fontNames.Save(source.styles[sty].fontName);
99 nextExtendedStyle = source.nextExtendedStyle;
100 for (int mrk=0; mrk<=MARKER_MAX; mrk++) {
101 markers[mrk] = source.markers[mrk];
103 CalcLargestMarkerHeight();
104 for (int ind=0; ind<=INDIC_MAX; ind++) {
105 indicators[ind] = source.indicators[ind];
108 selColours = source.selColours;
109 selAdditionalForeground = source.selAdditionalForeground;
110 selAdditionalBackground = source.selAdditionalBackground;
111 selBackground2 = source.selBackground2;
112 selAlpha = source.selAlpha;
113 selAdditionalAlpha = source.selAdditionalAlpha;
114 selEOLFilled = source.selEOLFilled;
116 foldmarginColour = source.foldmarginColour;
117 foldmarginHighlightColour = source.foldmarginHighlightColour;
119 hotspotColours = source.hotspotColours;
120 hotspotUnderline = source.hotspotUnderline;
121 hotspotSingleLine = source.hotspotSingleLine;
123 whitespaceColours = source.whitespaceColours;
124 controlCharSymbol = source.controlCharSymbol;
125 controlCharWidth = source.controlCharWidth;
126 selbar = source.selbar;
127 selbarlight = source.selbarlight;
128 caretcolour = source.caretcolour;
129 additionalCaretColour = source.additionalCaretColour;
130 showCaretLineBackground = source.showCaretLineBackground;
131 alwaysShowCaretLineBackground = source.alwaysShowCaretLineBackground;
132 caretLineBackground = source.caretLineBackground;
133 caretLineAlpha = source.caretLineAlpha;
134 edgecolour = source.edgecolour;
135 edgeState = source.edgeState;
136 caretStyle = source.caretStyle;
137 caretWidth = source.caretWidth;
138 someStylesProtected = false;
139 someStylesForceCase = false;
140 leftMarginWidth = source.leftMarginWidth;
141 rightMarginWidth = source.rightMarginWidth;
142 for (int margin=0; margin <= SC_MAX_MARGIN; margin++) {
143 ms[margin] = source.ms[margin];
145 maskInLine = source.maskInLine;
146 fixedColumnWidth = source.fixedColumnWidth;
147 marginInside = source.marginInside;
148 textStart = source.textStart;
149 zoomLevel = source.zoomLevel;
150 viewWhitespace = source.viewWhitespace;
151 whitespaceSize = source.whitespaceSize;
152 viewIndentationGuides = source.viewIndentationGuides;
153 viewEOL = source.viewEOL;
154 extraFontFlag = source.extraFontFlag;
155 extraAscent = source.extraAscent;
156 extraDescent = source.extraDescent;
157 marginStyleOffset = source.marginStyleOffset;
158 annotationVisible = source.annotationVisible;
159 annotationStyleOffset = source.annotationStyleOffset;
160 braceHighlightIndicatorSet = source.braceHighlightIndicatorSet;
161 braceHighlightIndicator = source.braceHighlightIndicator;
162 braceBadLightIndicatorSet = source.braceBadLightIndicatorSet;
163 braceBadLightIndicator = source.braceBadLightIndicator;
165 theEdge = source.theEdge;
167 marginNumberPadding = source.marginNumberPadding;
168 ctrlCharPadding = source.ctrlCharPadding;
169 lastSegItalicsOffset = source.lastSegItalicsOffset;
171 wrapState = source.wrapState;
172 wrapVisualFlags = source.wrapVisualFlags;
173 wrapVisualFlagsLocation = source.wrapVisualFlagsLocation;
174 wrapVisualStartIndent = source.wrapVisualStartIndent;
175 wrapIndentMode = source.wrapIndentMode;
178 ViewStyle::~ViewStyle() {
179 styles.clear();
180 for (FontMap::iterator it = fonts.begin(); it != fonts.end(); ++it) {
181 delete it->second;
183 fonts.clear();
186 void ViewStyle::Init(size_t stylesSize_) {
187 AllocStyles(stylesSize_);
188 nextExtendedStyle = 256;
189 fontNames.Clear();
190 ResetDefaultStyle();
192 // There are no image markers by default, so no need for calling CalcLargestMarkerHeight()
193 largestMarkerHeight = 0;
195 indicators[0].style = INDIC_SQUIGGLE;
196 indicators[0].under = false;
197 indicators[0].fore = ColourDesired(0, 0x7f, 0);
198 indicators[1].style = INDIC_TT;
199 indicators[1].under = false;
200 indicators[1].fore = ColourDesired(0, 0, 0xff);
201 indicators[2].style = INDIC_PLAIN;
202 indicators[2].under = false;
203 indicators[2].fore = ColourDesired(0xff, 0, 0);
205 technology = SC_TECHNOLOGY_DEFAULT;
206 lineHeight = 1;
207 maxAscent = 1;
208 maxDescent = 1;
209 aveCharWidth = 8;
210 spaceWidth = 8;
211 tabWidth = spaceWidth * 8;
213 selColours.fore = ColourOptional(ColourDesired(0xff, 0, 0));
214 selColours.back = ColourOptional(ColourDesired(0xc0, 0xc0, 0xc0), true);
215 selAdditionalForeground = ColourDesired(0xff, 0, 0);
216 selAdditionalBackground = ColourDesired(0xd7, 0xd7, 0xd7);
217 selBackground2 = ColourDesired(0xb0, 0xb0, 0xb0);
218 selAlpha = SC_ALPHA_NOALPHA;
219 selAdditionalAlpha = SC_ALPHA_NOALPHA;
220 selEOLFilled = false;
222 foldmarginColour = ColourOptional(ColourDesired(0xff, 0, 0));
223 foldmarginHighlightColour = ColourOptional(ColourDesired(0xc0, 0xc0, 0xc0));
225 whitespaceColours.fore = ColourOptional();
226 whitespaceColours.back = ColourOptional(ColourDesired(0xff, 0xff, 0xff));
227 controlCharSymbol = 0; /* Draw the control characters */
228 controlCharWidth = 0;
229 selbar = Platform::Chrome();
230 selbarlight = Platform::ChromeHighlight();
231 styles[STYLE_LINENUMBER].fore = ColourDesired(0, 0, 0);
232 styles[STYLE_LINENUMBER].back = Platform::Chrome();
233 caretcolour = ColourDesired(0, 0, 0);
234 additionalCaretColour = ColourDesired(0x7f, 0x7f, 0x7f);
235 showCaretLineBackground = false;
236 alwaysShowCaretLineBackground = false;
237 caretLineBackground = ColourDesired(0xff, 0xff, 0);
238 caretLineAlpha = SC_ALPHA_NOALPHA;
239 edgecolour = ColourDesired(0xc0, 0xc0, 0xc0);
240 edgeState = EDGE_NONE;
241 caretStyle = CARETSTYLE_LINE;
242 caretWidth = 1;
243 someStylesProtected = false;
244 someStylesForceCase = false;
246 hotspotColours.fore = ColourOptional(ColourDesired(0, 0, 0xff));
247 hotspotColours.back = ColourOptional(ColourDesired(0xff, 0xff, 0xff));
248 hotspotUnderline = true;
249 hotspotSingleLine = true;
251 leftMarginWidth = 1;
252 rightMarginWidth = 1;
253 ms[0].style = SC_MARGIN_NUMBER;
254 ms[0].width = 0;
255 ms[0].mask = 0;
256 ms[1].style = SC_MARGIN_SYMBOL;
257 ms[1].width = 16;
258 ms[1].mask = ~SC_MASK_FOLDERS;
259 ms[2].style = SC_MARGIN_SYMBOL;
260 ms[2].width = 0;
261 ms[2].mask = 0;
262 marginInside = true;
263 fixedColumnWidth = marginInside ? leftMarginWidth : 0;
264 maskInLine = 0xffffffff;
265 for (int margin=0; margin <= SC_MAX_MARGIN; margin++) {
266 fixedColumnWidth += ms[margin].width;
267 if (ms[margin].width > 0)
268 maskInLine &= ~ms[margin].mask;
270 textStart = marginInside ? fixedColumnWidth : leftMarginWidth;
271 zoomLevel = 0;
272 viewWhitespace = wsInvisible;
273 whitespaceSize = 1;
274 viewIndentationGuides = ivNone;
275 viewEOL = false;
276 extraFontFlag = 0;
277 extraAscent = 0;
278 extraDescent = 0;
279 marginStyleOffset = 0;
280 annotationVisible = ANNOTATION_HIDDEN;
281 annotationStyleOffset = 0;
282 braceHighlightIndicatorSet = false;
283 braceHighlightIndicator = 0;
284 braceBadLightIndicatorSet = false;
285 braceBadLightIndicator = 0;
287 theEdge = 0;
289 marginNumberPadding = 3;
290 ctrlCharPadding = 3; // +3 For a blank on front and rounded edge each side
291 lastSegItalicsOffset = 2;
293 wrapState = eWrapNone;
294 wrapVisualFlags = 0;
295 wrapVisualFlagsLocation = 0;
296 wrapVisualStartIndent = 0;
297 wrapIndentMode = SC_WRAPINDENT_FIXED;
300 void ViewStyle::Refresh(Surface &surface, int tabInChars) {
301 for (FontMap::iterator it = fonts.begin(); it != fonts.end(); ++it) {
302 delete it->second;
304 fonts.clear();
306 selbar = Platform::Chrome();
307 selbarlight = Platform::ChromeHighlight();
309 for (unsigned int i=0; i<styles.size(); i++) {
310 styles[i].extraFontFlag = extraFontFlag;
313 CreateAndAddFont(styles[STYLE_DEFAULT]);
314 for (unsigned int j=0; j<styles.size(); j++) {
315 CreateAndAddFont(styles[j]);
318 for (FontMap::iterator it = fonts.begin(); it != fonts.end(); ++it) {
319 it->second->Realise(surface, zoomLevel, technology, it->first);
322 for (unsigned int k=0; k<styles.size(); k++) {
323 FontRealised *fr = Find(styles[k]);
324 styles[k].Copy(fr->font, *fr);
326 maxAscent = 1;
327 maxDescent = 1;
328 FindMaxAscentDescent();
329 maxAscent += extraAscent;
330 maxDescent += extraDescent;
331 lineHeight = maxAscent + maxDescent;
333 someStylesProtected = false;
334 someStylesForceCase = false;
335 for (unsigned int l=0; l<styles.size(); l++) {
336 if (styles[l].IsProtected()) {
337 someStylesProtected = true;
339 if (styles[l].caseForce != Style::caseMixed) {
340 someStylesForceCase = true;
344 aveCharWidth = styles[STYLE_DEFAULT].aveCharWidth;
345 spaceWidth = styles[STYLE_DEFAULT].spaceWidth;
346 tabWidth = spaceWidth * tabInChars;
348 controlCharWidth = 0.0;
349 if (controlCharSymbol >= 32) {
350 controlCharWidth = surface.WidthChar(styles[STYLE_CONTROLCHAR].font, static_cast<char>(controlCharSymbol));
353 fixedColumnWidth = marginInside ? leftMarginWidth : 0;
354 maskInLine = 0xffffffff;
355 for (int margin=0; margin <= SC_MAX_MARGIN; margin++) {
356 fixedColumnWidth += ms[margin].width;
357 if (ms[margin].width > 0)
358 maskInLine &= ~ms[margin].mask;
360 textStart = marginInside ? fixedColumnWidth : leftMarginWidth;
363 void ViewStyle::ReleaseAllExtendedStyles() {
364 nextExtendedStyle = 256;
367 int ViewStyle::AllocateExtendedStyles(int numberStyles) {
368 int startRange = static_cast<int>(nextExtendedStyle);
369 nextExtendedStyle += numberStyles;
370 EnsureStyle(nextExtendedStyle);
371 for (size_t i=startRange; i<nextExtendedStyle; i++) {
372 styles[i].ClearTo(styles[STYLE_DEFAULT]);
374 return startRange;
377 void ViewStyle::EnsureStyle(size_t index) {
378 if (index >= styles.size()) {
379 AllocStyles(index+1);
383 void ViewStyle::ResetDefaultStyle() {
384 styles[STYLE_DEFAULT].Clear(ColourDesired(0,0,0),
385 ColourDesired(0xff,0xff,0xff),
386 Platform::DefaultFontSize() * SC_FONT_SIZE_MULTIPLIER, fontNames.Save(Platform::DefaultFont()),
387 SC_CHARSET_DEFAULT,
388 SC_WEIGHT_NORMAL, false, false, false, Style::caseMixed, true, true, false);
391 void ViewStyle::ClearStyles() {
392 // Reset all styles to be like the default style
393 for (unsigned int i=0; i<styles.size(); i++) {
394 if (i != STYLE_DEFAULT) {
395 styles[i].ClearTo(styles[STYLE_DEFAULT]);
398 styles[STYLE_LINENUMBER].back = Platform::Chrome();
400 // Set call tip fore/back to match the values previously set for call tips
401 styles[STYLE_CALLTIP].back = ColourDesired(0xff, 0xff, 0xff);
402 styles[STYLE_CALLTIP].fore = ColourDesired(0x80, 0x80, 0x80);
405 void ViewStyle::SetStyleFontName(int styleIndex, const char *name) {
406 styles[styleIndex].fontName = fontNames.Save(name);
409 bool ViewStyle::ProtectionActive() const {
410 return someStylesProtected;
413 int ViewStyle::ExternalMarginWidth() const {
414 return marginInside ? 0 : fixedColumnWidth;
417 bool ViewStyle::ValidStyle(size_t styleIndex) const {
418 return styleIndex < styles.size();
421 void ViewStyle::CalcLargestMarkerHeight() {
422 largestMarkerHeight = 0;
423 for (int m = 0; m <= MARKER_MAX; ++m) {
424 switch (markers[m].markType) {
425 case SC_MARK_PIXMAP:
426 if (markers[m].pxpm && markers[m].pxpm->GetHeight() > largestMarkerHeight)
427 largestMarkerHeight = markers[m].pxpm->GetHeight();
428 break;
429 case SC_MARK_RGBAIMAGE:
430 if (markers[m].image && markers[m].image->GetHeight() > largestMarkerHeight)
431 largestMarkerHeight = markers[m].image->GetHeight();
432 break;
437 // See if something overrides the line background color: Either if caret is on the line
438 // and background color is set for that, or if a marker is defined that forces its background
439 // color onto the line, or if a marker is defined but has no selection margin in which to
440 // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
441 // with the earlier taking precedence. When multiple markers cause background override,
442 // the color for the highest numbered one is used.
443 ColourOptional ViewStyle::Background(int marksOfLine, bool caretActive, bool lineContainsCaret) const {
444 ColourOptional background;
445 if ((caretActive || alwaysShowCaretLineBackground) && showCaretLineBackground && (caretLineAlpha == SC_ALPHA_NOALPHA) && lineContainsCaret) {
446 background = ColourOptional(caretLineBackground, true);
448 if (!background.isSet && marksOfLine) {
449 int marks = marksOfLine;
450 for (int markBit = 0; (markBit < 32) && marks; markBit++) {
451 if ((marks & 1) && (markers[markBit].markType == SC_MARK_BACKGROUND) &&
452 (markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
453 background = ColourOptional(markers[markBit].back, true);
455 marks >>= 1;
458 if (!background.isSet && maskInLine) {
459 int marksMasked = marksOfLine & maskInLine;
460 if (marksMasked) {
461 for (int markBit = 0; (markBit < 32) && marksMasked; markBit++) {
462 if ((marksMasked & 1) && (markers[markBit].markType != SC_MARK_EMPTY) &&
463 (markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
464 background = ColourOptional(markers[markBit].back, true);
466 marksMasked >>= 1;
470 return background;
474 ColourDesired ViewStyle::WrapColour() const {
475 if (whitespaceColours.fore.isSet)
476 return whitespaceColours.fore;
477 else
478 return styles[STYLE_DEFAULT].fore;
481 bool ViewStyle::SetWrapState(int wrapState_) {
482 WrapMode wrapStateWanted;
483 switch (wrapState_) {
484 case SC_WRAP_WORD:
485 wrapStateWanted = eWrapWord;
486 break;
487 case SC_WRAP_CHAR:
488 wrapStateWanted = eWrapChar;
489 break;
490 case SC_WRAP_WHITESPACE:
491 wrapStateWanted = eWrapWhitespace;
492 break;
493 default:
494 wrapStateWanted = eWrapNone;
495 break;
497 bool changed = wrapState != wrapStateWanted;
498 wrapState = wrapStateWanted;
499 return changed;
502 bool ViewStyle::SetWrapVisualFlags(int wrapVisualFlags_) {
503 bool changed = wrapVisualFlags != wrapVisualFlags_;
504 wrapVisualFlags = wrapVisualFlags_;
505 return changed;
508 bool ViewStyle::SetWrapVisualFlagsLocation(int wrapVisualFlagsLocation_) {
509 bool changed = wrapVisualFlagsLocation != wrapVisualFlagsLocation_;
510 wrapVisualFlagsLocation = wrapVisualFlagsLocation_;
511 return changed;
514 bool ViewStyle::SetWrapVisualStartIndent(int wrapVisualStartIndent_) {
515 bool changed = wrapVisualStartIndent != wrapVisualStartIndent_;
516 wrapVisualStartIndent = wrapVisualStartIndent_;
517 return changed;
520 bool ViewStyle::SetWrapIndentMode(int wrapIndentMode_) {
521 bool changed = wrapIndentMode != wrapIndentMode_;
522 wrapIndentMode = wrapIndentMode_;
523 return changed;
526 void ViewStyle::AllocStyles(size_t sizeNew) {
527 size_t i=styles.size();
528 styles.resize(sizeNew);
529 if (styles.size() > STYLE_DEFAULT) {
530 for (; i<sizeNew; i++) {
531 if (i != STYLE_DEFAULT) {
532 styles[i].ClearTo(styles[STYLE_DEFAULT]);
538 void ViewStyle::CreateAndAddFont(const FontSpecification &fs) {
539 if (fs.fontName) {
540 FontMap::iterator it = fonts.find(fs);
541 if (it == fonts.end()) {
542 fonts[fs] = new FontRealised();
547 FontRealised *ViewStyle::Find(const FontSpecification &fs) {
548 if (!fs.fontName) // Invalid specification so return arbitrary object
549 return fonts.begin()->second;
550 FontMap::iterator it = fonts.find(fs);
551 if (it != fonts.end()) {
552 // Should always reach here since map was just set for all styles
553 return it->second;
555 return 0;
558 void ViewStyle::FindMaxAscentDescent() {
559 for (FontMap::const_iterator it = fonts.begin(); it != fonts.end(); ++it) {
560 if (maxAscent < it->second->ascent)
561 maxAscent = it->second->ascent;
562 if (maxDescent < it->second->descent)
563 maxDescent = it->second->descent;